使用setnx命令,在SpringBoot中为setIfAbsent,最简单的代码以下:redis
固然上述代码会存在问题,如A服务在执行到中间时抛异常,则不能释放这个锁,加上try-catch-finally,以下:架构
可是若是在中间的时候直接断掉,则仍然不能释放锁,加上锁的自动释放时间,以下:并发
可是这个不能保证原子性,若是在正好执行到设置过时时间以前断掉,则仍然不能释放锁,放在一条执行语句里面,以下:框架
可是在高并发状况下,线程一须要15秒,线程二须要8秒,线程一执行到第十秒会自动释放锁,这时线程二会拿到锁,线程二执行了五秒后,线程一也执行了五秒,这时一会执行finally里的代码释放锁,可是这个锁倒是二的,这时线程三又会拿到这个锁去执行。。。如此下去会永久失效分布式
解决问题的根本点:本身的锁被别人释放掉高并发
解决方式:使用惟一id,只有是本身的锁才会本身去释放代码以下:性能
可是这里仍然会有超时问题,设置短了太容易超时,设置长了不利于锁的释放。lua
使用从线程定时任务去执行监控主线程看看是否还在执行,若是是,则从新把超时时间延长,这也是一种解决方式。spa
使用框架一步解决问题:线程
实现原理以下图:
里面的lock方法的最核心部分就是执行了一个lua脚本,保证了加锁和设置过时时间的原子性,原理如上图
上图所示的redis是主从架构,当Master宕机可是仍然未同步到从节点的时候,从节点会选举出新的主节点,可是这是没有加锁的,这是由于Redission的分布式锁是知足AP的,即知足可用性,不知足一致性,只要主节点写了一个key,立马告诉redission客户端(不一样于zookeeper的分布式锁是知足CP,zookeeper主节点获取key以后,超过半数的从节点同步以后才会返回,即知足一致性)
这个问题使用redis的Redlock能够解决(原理和zookeeper相似),可是牺牲了性能,并不推荐使用