多线程的经典案例(卖票)
前两天在站内看到几个多线程卖票的案例,发现代码都不怎么对,运行结果也不符合预期,不能有效复现多线程并发的场景。故而自己写了一套,过程中也产生了一些新的思考,在此梳理一下。
先贴代码,假设现在电影院有100张票,3个窗口同时售卖。
public class NewTask implements Runnable { public int num = 100; @Override public void run() { while(num > 0) { try { Thread.sleep(20); } catch (InterruptedException e) { e.printStackTrace(); } String name = Thread.currentThread().getName(); System.out.println(name + "窗口正在卖" + num--); } } }
这里有一个重点:就是使用sleep()模拟售票业务时间,如果不加,大概率不会出现并发问题,因为剩余代码所需执行时间极短,一个时间片内足以跑完。有兴趣的同学可以试试
测试类
public class Why { public static void main(String[] args) { NewTask newTask = new NewTask(); Thread thread1 = new Thread(newTask, "1号"); Thread thread2 = new Thread(newTask, "2号"); Thread thread3 = new Thread(newTask, "3号"); thread1.start(); thread2.start(); thread3.start(); } }
部分执行结果如下,同一张票被多个窗口卖出,成功复现了多线程并发问题,符合我们的预期。
至于解决并发无非就是加锁,保证访问共享资源的操作原子性。加锁方式很多,大家可以自行百度,这边我就贴个最简单的就是synchronized关键字。
public class NewTask implements Runnable { public int num = 100; @Override public void run() { synchronized (NewTask.class) { while(num > 0) { try { Thread.sleep(20); } catch (InterruptedException e) { e.printStackTrace(); } String name = Thread.currentThread().getName(); System.out.println(name + "窗口正在卖" + num--); } } } }