Java学习笔记——Lock锁解决线程安全问题

    技术2022-07-11  76

    今天学习Java线程同步时,写了下面代码,表示有三个窗口(线程)同时卖100张票的多线程情形。在使用Lock锁保证线程安全时,l.unlock()写的是有点问题的,后面修改为正确写法。

    public class TestSellTicket { public static void main(String[] args) { RunnableImpl runnable = new RunnableImpl(); System.out.println("runnable: " + runnable); // 开启三个线程,共享RunnableImpl中的ticket数据 new Thread(runnable).start(); new Thread(runnable).start(); new Thread(runnable).start(); // 不使用同步,可能出现都卖第10张票,卖第0张票 } }

    有问题的写法:

    public class RunnableImpl implements Runnable { private int ticket = 100; // 共享数据 private ReentrantLock l = new ReentrantLock(); @Override public void run() { while (true) { l.lock(); if (ticket > 0) { try { // 让程序睡眠,增大线程安全问题出现的概率 Thread.sleep(10); System.out.println(Thread.currentThread().getName() + "正在卖第" + ticket + "张票"); ticket--; } catch (Exception e) { e.printStackTrace(); } finally { l.unlock(); } } else { break; } } } }

    程序不会正常结束,但输出结果显示是线程安全的:

    ... Thread-0正在卖第30张票 Thread-0正在卖第29张票 Thread-0正在卖第28张票 Thread-2正在卖第27张票 Thread-2正在卖第26张票 ...

    这里问题主要出在忽略了else情形下(即ticket值为0时),锁忘记归还就跳出循环结束了,导致其他线程一直处于阻塞状态,所以显示程序一直没有正常结束。解决只要加上l.unlock()即可。

    public class RunnableImpl implements Runnable { private int ticket = 100; // 共享数据 private ReentrantLock l = new ReentrantLock(); @Override public void run() { while (true) { l.lock(); if (ticket > 0) { try { // 让程序睡眠,增大线程安全问题出现的概率 Thread.sleep(10); System.out.println(Thread.currentThread().getName() + "正在卖第" + ticket + "张票"); ticket--; } catch (Exception e) { e.printStackTrace(); } finally { l.unlock(); } } else { l.unlock(); break; } } } }
    Processed: 0.014, SQL: 9