5.zk实现-分布式排它锁

来源:互联网 发布:2017手机淘宝装修教程 编辑:程序博客网 时间:2024/05/29 09:32

1.介绍

排它锁::也场称为写锁,某个时间段内只允许一个事务持有锁,其他事务等他别人释放

2.实现思路

(1)定义锁:

创建一个数据节点test/lock来表示锁。test是持久节点,lock为子节点临时节点。

(2)获取锁:

所有客户端的zk实例尝试创建一个lock节点,最终只能有一个创建成功。创建成功的zk实例认为获取锁执行自己的server逻辑,创建失败的锁需要监听test下面子节点变更的watcher来监听别人是否释放了锁。

(3)释放锁:

创建成功的zk实例在机器宕机(zk实例销毁)时zk自动删除lock节点。或者server逻辑执行完毕之后zk实例主动删除结点,其他监听的zk实例再去争夺锁。


(4)整个过程:
zk实例监听watcher然后尝试创建节点。
如果创建成功在回调方法中执行业务逻辑然后监听watcher释放节点发出delete-event给其他监听者。
如果创建失败在回调方法中监听watcher接收其他持锁者的delete-event。监听到持锁着的delete-event后在自己的回调中再次监听warcher并尝试创建节点。

3.测试

package zkTest.test;import java.io.IOException;import java.util.Date;import org.apache.zookeeper.CreateMode;  import org.apache.zookeeper.KeeperException;import org.apache.zookeeper.KeeperException.NodeExistsException;import org.apache.zookeeper.WatchedEvent;  import org.apache.zookeeper.Watcher;  import org.apache.zookeeper.Watcher.Event.EventType;  import org.apache.zookeeper.Watcher.Event.KeeperState;  import org.apache.zookeeper.ZooDefs.Ids;  import org.apache.zookeeper.ZooKeeper;    public class zk_locks implements Watcher {  //zk实例应该为类变量    private  ZooKeeper zk;      private  String path ;       //构造函数    public zk_locks(String zkServer,int timeOut,String path) throws IOException{        this.path = path;    this.zk=new ZooKeeper(zkServer, timeOut, this);    }               //创建节点    public  void createNode() throws KeeperException, InterruptedException {         zk.create(path,"".getBytes(),Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL);    }         //持锁成功后的业务逻辑,执行完释放锁    public void working(){        Thread thread = new Thread(new Runnable() {public void run() {try {    System.out.println(new Date()+"持有锁");Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();} finally {    try {    System.out.println(new Date()+"释放锁");    System.out.println("-------------------");    //主动释放锁zk.delete(path, 0);} catch (InterruptedException | KeeperException e) {e.printStackTrace();}}}});    thread.start();    }             //加锁与判断    public void doLock(){        try {        //监听这个节点触发回调,注册一次就触发一次        zk.exists(path, true);        //创建成功,回调函数NodeCreated        //或者创建失败,抛出节点存在异常,回调函数None        this.createNode();}         catch (NodeExistsException e) {System.out.println("节点已存在,准备重试");}        catch (InterruptedException | KeeperException e) {        e.printStackTrace();}    }      @Override        public void process(WatchedEvent event) {          try {              if (KeeperState.SyncConnected == event.getState()) {                if (EventType.None == event.getType() && null == event.getPath()) {                  //第一次创建失败到这里,说明节点已存在,只能监听别人的delete事件                zk.exists(path, true);                }                 //节点创建事件                else if (EventType.NodeCreated == event.getType()) {                  this.working();                }                 //节点删除事件                else if (EventType.NodeDeleted == event.getType()) {                  //监听到比人的delete事件,我再次加锁,可能成功也可能再次失败                this.doLock();                }              }          } catch (Exception e) {              e.printStackTrace();          }      }        public static void main(String[] args) throws KeeperException, InterruptedException, IOException{          //五个同时加锁    new zk_locks("192.168.88.131:2181", 10000, "/lock").doLock();    new zk_locks("192.168.88.131:2181", 10000, "/lock").doLock();    new zk_locks("192.168.88.131:2181", 10000, "/lock").doLock();    new zk_locks("192.168.88.131:2181", 10000, "/lock").doLock();    new zk_locks("192.168.88.131:2181", 10000, "/lock").doLock();     //等待工作进程从开始到结束    Thread.sleep(10000);    }    } 

4.测试结果



原创粉丝点击