zookeeper实现分布式锁-curator框架
zookeeper基于文件系统+通知机制,zookeeper的节点是树状的,每一个节点为一个znode。通过zookeeper客户端可以去创建节点,创建的节点有很多种。永久节点、永久节点带序号、临时节点、临时节点带序号等等。
1 | public enum CreateMode { |
实现分布式锁
zookeeper的分布式锁实现方式比较简便,因为zookeeper是由一个一个znode组成,那么定义一个节点为:“/lock”,每次请求时,通过zookeeper创建一个带有顺序的临时节点,并且每一个节点都有一个WatchEvent,通过监听上一个节点来判断是否获取到锁。对于获取到锁的线程当执行完毕后删除对应的节点即可。
1. 创建当前路径的节点
1 | import org.apache.zookeeper.CreateMode; |
2.获取锁
2.1 首先获取到所有的子节点,并进行排序。
1 | private List<String> getSortedChildren() { |
判断当前创建的节点的路径,是否存在于所有子节点中。
存在,并且index == 0, 则直接获取到锁;
不存在,抛异常;
存在,并且index != 1,则监听前一个节点。
1 | private boolean internalLockLoop(long startMillis, Long millisToWait, String ourPath) throws KeeperException, InterruptedException { |
2.2 释放锁
释放锁的时候,直接删除当前路径就可以了。
1 | private void deletePath(String path) { |
完整代码
创建节点 InternalsDriver
1 | import org.apache.zookeeper.CreateMode; |
锁 DistributeLock
1 | import org.apache.zookeeper.KeeperException; |
测试类
1 | import org.apache.zookeeper.ZooKeeper; |
结果打印:
1 | ourPath:lock-0000000042 |
curator框架创建zookeeper分布式锁
引入依赖:
1 | <dependency> |
创建curator客户端并启动
1 | CuratorFramework curatorClient = CuratorFrameworkFactory.builder().connectString("localhost:2181") |
调用acquire获取锁,release释放锁就可以了
1 | CuratorFramework curatorClient = CuratorFrameworkFactory.builder().connectString("localhost:2181") |
打印结果
1 | 线程B获取到锁 |
上面自己实现的分布式锁,是参照curator的源码实现的
源码中,在获取锁的时候,增加了可重入锁
1 | /** key 线程, value, 持有的线程、路径、重入次数 **/ |