有个小伙伴提了个Java多线程卖票的例子,问为什么出现负数票。试着在电脑上运行了一下,最终得出答案,这里做个笔记,也希望对大家有益。
假设原题
- public class TicketThread implements Runnable {
- static int tickets = 100;// 火车票数量
- @Override
- public void run() {
- // 出售火车票
- while (tickets>0) {
- method();
- }
- }
- private void method() {
- if (tickets > 0) {
- try {
- /*
- * 1.为什么会出现负数票
- * 2.分析
- * (1)当票数等于 1 的时候 可能有 2 个线程判断完 if 语句但是,还在休眠
- * (2)休眠结束后 继续执行卖票环节
- * (3)出现负数票
- */
- Thread.sleep(10);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println(Thread.currentThread().getName() + “:” + tickets–);
- }
- }
- public static void main(String[] args) {
- TicketThread ticketThread = new TicketThread();
- Thread t1 = new Thread(ticketThread,“甲站台”);
- Thread t2 = new Thread(ticketThread,“乙站台”);
- Thread t3 = new Thread(ticketThread,“丙站台”);
- Thread t4 = new Thread(ticketThread,“丁站台”);
- t1.start();
- t2.start();
- t3.start();
- t4.start();
- }
- }
运行后,可能会出现 负数票,如下
分析:为什么会如此。我们可以假设,当只有一张票的时候,乙,甲、丙和丁四个线程依次加入就绪队列,乙线程先获得 CPU 执行权,通过 if 语句,然后在 sleep(10)下休眠(注意,就是这个地方),也就是在这短时间,加、丙和丁线程也依次通过了 if 语句。10 ms 后,乙线程 执行下面的打印票信息,即 1 号票,然后,另外三个线程也依次苏醒,输出 0 号票,-1 号票,-2 号票。
解决方案:让 “打印票信息和 tickets–”在 sleep(10) 前面 输出,不给其他线程“趁机”溜进来的机会。当然,我们这里的 sleep 休眠的时间不能设置太短,10ms 以上为好,如果是 1ms 就不太好。