这篇文章主要介绍“如何使用ZooKeeper实现Java跨JVM的分布式锁 ”,在日常操作中,相信很多人在如何使用ZooKeeper实现Java跨JVM的分布式锁 问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何使用ZooKeeper实现Java跨JVM的分布式锁 ”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!一、使用ZooKeeper实现Java跨JVM的分布式锁Zookeeper版本为Release 3.4.8(stable)
Curator版本为2.9.1锁原理:1、首先要创建一个锁的根节点,比如/mylock。2、想要获取锁的客户端在锁的根节点下面创建znode,作为/mylock的子节点,节点的类型要选择CreateMode.PERSISTENT_SEQUENTIAL,节点的名字最好用uuid(至于为什么用uuid我后面会讲,先说一下~如果不这么做在某种情况下会发生死锁,这一点我看了很多国内朋友自己的实现,都没有考虑到这一层,这也是我为什么不建议大家自己去封装这种锁,因为它确实很复杂),假设目前同时有3个客户端想要获得锁,那么/mylock下的目录应该是这个样子的。xxx-lock-0000000001,xxx-lock-0000000002,xxx-lock-0000000003
xxx为uuid ,0000000001,0000000002,0000000003 是zook服务端自动生成的自增数字。3、当前客户端通过getChildren(/mylock)获取所有子节点列表并根据自增数字排序,然后判断一下自己创建的节点的顺序是不是在列表当中最小的,如果是 那么获取到锁,如果不是,那么获取自己的前一个节点,并设置监听这个节点的变化,当节点变化时重新执行步骤3 直到自己是编号最小的一个为止。举例:假设当前客户端创建的节点是0000000002,因为它的编号不是最小的,所以获取不到锁,那么它就找到它前面的一个节点0000000001 并对它设置监听。4、释放锁,当前获得锁的客户端在操作完成后删除自己创建的节点,这样会激发zook的事件给其它客户端知道,这样其它客户端会重新执行(步骤3)。举例:加入客户端0000000001获取到锁,然后客户端0000000002加入进来获取锁,发现自己不是编号最小的,那么它会监听它前面节点的事件(0000000001的事件)然后执行步骤(3),当客户端0000000001操作完成后删除自己的节点,这时zook服务端会发送事件,这时客户端0000000002会接收到该事件,然后重复步骤3直到获取到锁)上面的步骤实现了一个有序锁,也就是先进入等待锁的客户端在锁可用时先获得锁。如果想要实现一个随机锁,那么只需要把PERSISTENT_SEQUENTIAL换成一个随机数即可。简单示例:
上面代码再获取锁的地方暂停了10秒钟,我们使用zook的客户端去查看目录的创建情况,由于我前面已经做了几次测试,所以序号是从12开始的。
模拟多个客户端(也可以认为是多个JVM):现在把上面的代码改造一下放入到线程中去执行,模拟多个客户端测试。
通过客户端软件我们可以看到10个申请锁的节点已经被创建出来了。
看一下打印结果,先申请获取锁的线程在锁可用时最先获取到锁,因为他们申请锁时创建节点的顺序号是递增的,先申请锁的客户端创建的节点编号最小,所以先获取到锁
为什么节点的名称要加上uuid,这是框架的英文解释。It turns out there is an edge case that exists when creating sequential-ephemeral nodes. The creation can succeed on the server, but the server can crash before the created node name is returned to the client. However, the ZK session is still valid so the ephemeral node is not deleted. Thus, there is no way for the client to determine what node was created for them.
Even without sequential-ephemeral, however, the create can succeed on the sever but the client (for various reasons) will not know it.
Putting the create builder into protection mode works around this. The name of the node that is created is prefixed with a GUID. If node creation fails the normal retry mechanism will occur. On the retry, the parent path is first searched for a node that has the GUID in it. If that node is found, it is assumed to be the lost node that was successfully created on the first try and is returned to the caller.
就是说 当客户端创建了一个节点,这个创建的过程在zook的服务器端已经成功了,但是在将节点的路径返回给客户端之前服务器端挂了, 因为客户端的session还是有效的,所以这个节点不会删除, 这样客户端就不知道哪个节点是它创建的。当客户端发生创建失败的时候,会进行重试,如果这个时候zook已经恢复可用,那么客户端会查询服务器端所有子节点,然后通过和自己创建的uuid对比,如果找到了,说明这个节点是它之前创建的,那么久直接使用它,不然这个节点就会成为一个死节点,导致死锁。实现非公平锁:重写创建节点的方法,把我们写的类注册进去:还开发云主机域名是上面的例子,在跑一边看结果,可以看到,获取锁的顺序已经是无序的了,从而实现了非公平锁。到此,关于“如何使用ZooKeeper实现Java跨JVM的分布式锁 ”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注开发云网站,小编会继续努力为大家带来更多实用的文章!
如何打开虚拟主机远程桌面?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。虚拟主机是无法打开远程桌面来管理的,虚拟主机一般采用控制面板、FTP软件等方式来管理。虚拟主机受技术原因,无法使用远程桌面…
免责声明:本站发布的图片视频文字,以转载和分享为主,文章观点不代表本站立场,本站不承担相关法律责任;如果涉及侵权请联系邮箱:360163164@qq.com举报,并提供相关证据,经查实将立刻删除涉嫌侵权内容。