今天学习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; } } } }