多线程的经典案例(卖票)

前两天在站内看到几个多线程卖票的案例,发现代码都不怎么对,运行结果也不符合预期,不能有效复现多线程并发的场景。故而自己写了一套,过程中也产生了一些新的思考,在此梳理一下。

先贴代码,假设现在电影院有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--);
            }
        }
    }
}
经验分享 程序员 微信小程序 职场和发展