今天学习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张票
}
}
1 错误写法
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张票
...
2 正确写法
这里问题主要出在忽略了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;
}
}
}
}