背景:出库时,采用定时任务检查每个出库口的状态,出库口可用则选择一个该出库口的任务执行。
当切换出入库模式时,先判断是否有正在执行中的任务,没有执行中的任务时,才可以切换为入库模式。
♂️抽象一下:
线程一 | 线程二 |
---|---|
1.检查出库口状态 | a.判断执行中的任务数量 |
2.执行任务 | b.关闭出库口 |
两个线程分别在两个事务中执行,也属于两个不同线程。如果不加锁,难免会出现一些问题:
1.此时执行中的任务数量为0 ,执行过程如果是 a 1 2 b 或者 1 a 2 b ,只要满足b在1之后 a在2之前,就会出现冲突。最终的结果就是任务执行了,出库口被关闭了。
最简单的是添加悲观锁,同时只有一个线程被执行。
如果采用乐观锁的方式怎么解决呢?
分析:导致冲突的根本原因是对于 多个任务和一个出库口资源的竞争。站在线程一的角度,检查出库状态没有问题,在检查完成后一直到事务被提交,如果其他线程更改了出库口的状态,必然会出问题。站在线程二的角度,同理,在判断完任务数量之后,如果在事务提交之前,有其他改变了执行中的任务数量,也会出现问题。
乐观锁是在所竞争的资源上加锁。
如果给多个未执行的任务加锁,那么两个线程在执行完后,需要更新一下所有的任务。由于线程一最后本身就是更新了任务状态,所以只需要在线程二执行完成后,空更新一下所有的任务状态,看是否发生冲突。
如果给出库口加锁,同理也是只需要在线程一最后添加一个空更新出库口的操作,检查是否发生冲突。
再次判断如果按照a 1 2 b或者a 1 b 2 或者 1 a 2 b 或者 1 a b 2的方式执行时候发生线程冲突。
如果给出库口加锁,两个线程的操作变成下面的样子
线程一 | 线程二 |
---|---|
1.检查出库口状态 | a.判断执行中的任务数量 |
2.执行任务 | b.关闭出库口 |
3.空更新出库口 |
我们站台线程一角度分析,在执行完3之后,如果有冲突,直接回滚事务,所以说如果线程一能成功执行,那么就不会发生任务执行了,出库口状态异常的情况。
如果给所有任务加锁,两个线程的操作变成下面的样子
线程一 | 线程二 |
---|---|
1.检查出库口状态 | a.判断执行中的任务数量 |
2.执行任务 | b.关闭出库口 |
c.空更新所有的任务 |
同理,我们站在线程二分析会方便一点,如果线程二顺利执行,就不可能存在出库口被关闭,仍然存在任务数量不为0的情况。
考虑两种方式,肯定是选择出库口作为锁更合理。