更为极端的误删逻辑说明:
同样的是redis锁的一个周期,然后下面是一个线程
同样的是线程1一上来就申请锁,线程1现在持有锁之后,在执行业务逻辑过程中,他正准备删除锁,而且已经走到了判断锁标识的过程中,由于这把锁是自己的,因此肯定返回ok,紧接着就要执行释放锁的动作了。这里要注意的是判断锁标识和释放锁是两个动作,判断是成功的,正准备删除锁,产生了阻塞。JVM中有一个东西叫做垃圾回收,当我们JVM去做这种GC的时候,它其实是会阻塞我们所有的代码,因此此时就会产生阻塞。不是因为你的业务阻塞,而是因为JVM本身产生阻塞,是有这种可能性的。
一旦发生了阻塞,并且这个阻塞的时间如果足够长,就有可能触发锁的超时释放。
锁一旦超时释放,其他的线程又可以乘虚而入了,例如此时线程2进来,由于锁被释放掉了,因此它可以继续获取锁,可以开始执行自己的业务,而就在他获取锁成功的那一刻,如果GC结束了,阻塞结束,我们的线程恢复运行,此时它就会去执行释放锁的动作了,因为判断已经执行过了,它认为锁还是自己的,但现在锁已经是线程2的了。此时直接执行释放锁,于是就把线程2的锁给删掉了,有一次发生了误删。
此时又来个线程3,获取锁成功,然后执行自己业务,由此可见,这种并发的问题有一次发生了。
所以这次产生的原因是什么?我们做了判断,但是由于判断锁标识和释放锁是两个动作,这两个动作之间产生了阻塞,最后出现了问题。
扫描二维码关注公众号,回复:
17496477 查看本文章

因此要想避免这个问题的发生,我们必须确保判断锁的动作和释放锁的动作这两个得成一个原子性的操作,也就是说一起执行,不能出现间隔。
那我们怎么保证两个动作的原子性呢?这个问题下节分析。