概述
为了保证在高并发下,一个方法或者属性同一时间只能被同一个线程执行,单机部署下可以用ReentrantLock或者Synchronized进行互斥控制。分布式集群系统中就需要用分布式锁来解决。一般来说实现分布式锁有三种方式。
一、基于数据库实现排他锁
建一张表,设置方法名称字段唯一,在获取锁的时候可以通过两种方法:
1、直接insert,如果失败则已经存在锁了,获取锁失败,如果insert成功则获取锁成功,释放锁直接delete。
2、update,再加一个字段,锁的状态,先查寻,然后update,如果update没有影响一条数据,则表示获取锁失败。释放锁则把状态字段修改。
缺点:
1、依赖数据库的可用性
2、没有失效时间,一旦解锁失败其他线程将无法获取锁
3、只能是非阻塞的,因为insert会直接报错
4、非重入的
解决方案:
1、两个数据库双向同步
2、采用定时任务来删除数据库中的超时数据
3、insert的地方采用while循环,直到insert成功之后再返回成功
4、非重入问题可以再表中加字段,记录当前获得锁的机器的主机信息和线程信息,下次获取锁的时候先根据主机信息和线程信息及方法名称一起查,如果能查到的话,直接把锁给他。
二、基于redis实现
获取锁的时候直接setIfAbsent(),如果返回false则获取失败,如果true则获取成功。
缺点:在redis使用主从结构中存在明显缺陷,客户端A从master中获取到了锁,在master将锁同步到slave之前,如果master宕掉了。slave节点被晋升为master,另一个客户端B将可以获得之前被客户端A获取成功的锁。
redis锁的可重入问题,同一线程再次获取锁的时候,先将ThreadLocal中的值和Redis中的value进行比较,如果相同则表示该线程拥有这把锁。
三、基于zookeeper
zookeeper是一个树结构,Znode就是组成树的节点。
zk的四种节点类型
1、持久节点
2、持久顺序节点
3、临时节点
4、临时顺序节点
zk获取锁的方式,在一个持久节点下创建一个临时顺序节点,然后该持久节点下的所有临时顺序节点并排序,查看自己创建的这个临时顺序节点是不是排在最前面的,如果是的话则获取到锁,如果不是,则向排在它前面的一个节点注册watcher进行监听。因为是临时顺序节点,等任务完成删除或者节点崩溃都会删除对应的临时顺序节点。当他监听的节点被删除之后,它会再次查出所有临时节点并排序,看看自己是不是排在最前面的。
zookeeper第三方库Curator客户端,这个客户端中封装了一个可重入的锁服务。
缺点:性能上不如redis。zk也有可能带来并发问题,由于网络抖动,zk集群的session连接断了,zk会以为客户端挂了,删除临时顺序节点后其他客户端就可以获取到分布式锁了。不过zk有重试机制,一旦zk集群检测不到客户端的心跳,就会重试,多次重试后还不行的话才会删除临时节点。
最后
以上就是强健耳机为你收集整理的常见的三种实现分布式锁的方法的全部内容,希望文章能够帮你解决常见的三种实现分布式锁的方法所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复