持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第5天,点击查看活动详情
前言
在节假日,很多线路的火车票都是紧俏资源,为此,诞生了各种各样的抢票软件。火车票是允许多个窗口、多个渠道售票的。因此,行程、时间完全一致的某张火车票就成为了共享资源。
下面,我们使用多线程模拟多个窗口同事出售火车票的场景(只考虑直达列车)。应使用同步机制,避免同一张票被成功出售多次。
共享任务模式
参见如下代码,TicketTask代表售票任务,此处使用了同步代码块模式。注意:synchronized(this)这句代码,必须要位于while(tickets>0)之后,如果移动到while(tickets>0)之前,则所有的票只能被一个窗口售出。if(tickets>0)这句代码也必须要有,否则会出现票的数量为负数的情况。
1、定义售票任务
由于ticket是多线程共享资源,因此修改前需要使用synchronized同步块进行保护,否则并发售票的效果会出现错误值。
2、定义窗口类
每个窗口成为一个线程
3、使用多线程模拟多个窗口同时售票
使用多线程模拟多个窗口同时售票,这些窗口共享同一人物对象。注意:如果每个窗口都是用独立的任务对象,就不会出现资源竞争问题。TicketTask的成员变量ticket是多线程共享的资源。
程序运行结果如下:
窗口12售出:30
窗口14售出:29
窗口13售出:28
窗口13售出:27
窗口14售出:26
窗口12售出:25
窗口12售出:24
窗口13售出:23
窗口14售出:22
窗口13售出:21
窗口12售出:20
窗口14售出:19
窗口12售出:18
窗口14售出:17
窗口13售出:16
窗口12售出:15
窗口14售出:14
窗口13售出:13
窗口14售出:12
窗口13售出:11
窗口12售出:10
窗口13售出:9
窗口14售出:8
窗口12售出:7
窗口12售出:6
窗口14售出:5
窗口13售出:4
窗口14售出:3
窗口13售出:2
窗口12售出:1
总结
TicketTask中的Thread.sleep(100),这句代码放到synchronized()中和放到之外,差别很大。
放在同步块中,当前线程执行完所有代码之后,与排队线程再次产生竞争抢锁的关系,如果计算机速度快,可能出现所有任务被一个线程全部执行完成。
放在同步块之外,在while()循环内,表明当前线程完成售票后会有短暂的延迟,这样就不会和排队线程产生竞争关系,会出现多个线程交替执行的效果。