分布式锁解决的问题
分布式锁:是为了解决在集群环境下处于不同集群下的获取锁的问题,由于不同集群下的服务器属于不同的jvm所以synchronized加锁方式就不能满足要求了。因为如果在两台服务器下如果有两个线程分别在这两台服务器下那么如果第一个集群jvm1申请获取锁成功,第二个集群下的Jvm2获取依然会成功因为他们属于不同的集群或者说是jvm下所以jdk带来的加锁方式就不能达到效果了
分布式锁的实现
实现:可以使用redis加锁方式来实现,利用setnx命令如:set lock thread1 EX 10 NX。并且为了防止死锁设定绑定时间。可以获取锁,然后执行业务逻辑执行后,要先进行判断该所是否是这个线程自己的锁。原因:因为如果业务执行的时间超过了设置的key存在时间则可能会出现线程1释放了线程2的锁。
存在的问题
针对上面有一个问题:当线程一进行判断当前锁是否是自己如果是自己的就释放锁在释放在这期间由于jvm的垃圾回收机制可能会触发堵塞,此时线程2 在这个期间刚好获取了锁,那么当线程1释放锁结束时则释放的是线程2的锁。为了解决这个问题应该让判断和释放同时执行成功或者失败 。可以使用lua脚本或者乐观锁来解决
redission工具解决分布式锁问题
redission工具是基于redis的解决了分布式锁的问题。该工具可以代替自己实现
redisson的使用
- 导入redisson坐标,建议导入redisson的不要导入start的
- 运用配置类配置redisson
- 运用redisson,获取锁对象,获取锁,释放锁。
redission可重入锁原理
不可重入:指同一个线程多次获取一把锁的问题。当释放锁时会把锁直接释放而此时可能业务还没有完成就释放了,这样可能导致其他线程进来
可重入:利用hash数据结构,当线程获取锁时如果发现已经有人获取锁,要判断一下这个 人是不是自己,如果是自己在将获取锁的次数加1 ,如果不是则获取锁失败。
释放锁阶段:不是直接删除锁,而是去检查获取锁的次数,如果过去次数大于1则不能直接删锁而是把次数减1,而如果此时为0才能删除锁
利用redission解决如上的4给问题
- 可重入:上面已说
- 可重式:当获取锁失败后不会立即返回错误而是等待获取锁成功的线程给出释放锁信号,然后重新尝试获取,如果超市则失败
- 超时释放:每隔一段时间,充值超市时间,可以解决死锁问题
- 主从一致性:表示正在主从同步时宕机,此时锁失效,其他线程就可以获取锁了。原理利用redis节点,必须在所以节点获取重入锁,才算获取成功