基于zookeeper的分布式锁实现

来源:互联网 发布:java开发实战经典答案 编辑:程序博客网 时间:2024/05/22 00:37

之前已经实现过基于redis的分布式锁
这次用zookeeper来实现.

原理:ZooKeeper有四种形式的目录节点,四种CreateMode


  • PERSISTENT:持久化目录节点,存储的数据不会丢失。
  • PERSISTENT_SEQUENTIAL:顺序自动编号的持久化目录节点,存储的数据不会丢失,并且根据当前已近存在的节点数自动加 1,然后返回给客户端已经成功创建的目录节点名。
  • EPHEMERAL:临时目录节点,一旦创建这个节点的客户端与服务器端口也就是session 超时,这种节点会被自动删除。
  • EPHEMERAL_SEQUENTIAL:临时自动编号节点,一旦创建这个节点的客户端与服务器端口也就是session 超时,这种节点会被自动删除,并且根据当前已近存在的节点数自动加 1,然后返回给客户端已经成功创建的目录节点名。

用EPHEMERAL_SEQUENTIAL即可实现分布式锁.当获取锁的时候,节点会自动增加,如果你的节点是最小的,那么你就获取锁.不然就等待.(只需等待比你大的节点是否还存在,如果不存在,重复获取)

代码

package demo.zookeeper.lock;import demo.zookeeper.AbstractZooKeeper;import org.apache.zookeeper.CreateMode;import org.apache.zookeeper.KeeperException;import org.apache.zookeeper.ZooDefs;import org.apache.zookeeper.ZooKeeper;import java.io.IOException;import java.util.Comparator;import java.util.List;/** * 基于Zookeeper的分布式锁 * Created by yuyufeng on 2017/8/22. */public class LockUtil {    //锁失效时间10秒    private static final int TIME_OUT = 10000;    private static final String HOST = "localhost:2181";    private static ZooKeeper zookeeper;    private static String ROOT_PATH = "/lockdata";    static {        try {            zookeeper = new ZooKeeper(HOST, TIME_OUT, new AbstractZooKeeper());            try {                //建立锁节点存放根目录                if (zookeeper.exists(ROOT_PATH, false) == null) {                    zookeeper.create(ROOT_PATH, "true".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);                }            } catch (Exception e) {}        } catch (IOException e) {}    }    /**     * 获取一个锁     * @param key  同步监听对象     * @return     */    public static boolean getLock(String key) {        Long beginTime = System.currentTimeMillis();        try {            if (zookeeper.exists(ROOT_PATH + "/" + key, false) == null) {                zookeeper.create(ROOT_PATH + "/" + key, "true".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);            }        } catch (KeeperException e) {} catch (InterruptedException e) {}        String result = null;        try {            result = zookeeper.create(ROOT_PATH + "/" + key + "/", "true".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);        } catch (KeeperException e) {} catch (InterruptedException e) {}        result = result.substring(result.lastIndexOf("/") + 1, result.length());        return lockHandler(key, beginTime, result);    }    private static boolean lockHandler(String key, Long beginTime, String result){        List<String> list = null;        try {            list = zookeeper.getChildren(ROOT_PATH + "/" + key, false);        } catch (KeeperException e) {} catch (InterruptedException e) {}        if (list == null || list.size() == 0) {            System.out.println(Thread.currentThread().getName()+"获取锁异常,失败!");            return false;        }        System.out.println("==========================================");        list.sort(new Comparator<String>() {            @Override            public int compare(String o1, String o2) {                return Integer.valueOf(o1) - Integer.valueOf(o2);            }        });        System.out.println(Thread.currentThread().getName()+"获取锁结果: " + result + " :" + list.get(0));        if (result.equals(list.get(0))) {            System.out.println(Thread.currentThread().getName()+ROOT_PATH + "/" + key + " 获取锁成功");            return true;        }        //为获取锁失败,监听当前节点之前的节点,如之前的节点已经不存在,再次获取.        String beforeNode = list.get(0);        for (int i = 0; i < list.size(); i++) {            if (result.equals(list.get(i))) {                beforeNode = list.get(--i);                break;            }        }        //监听上一个节点5秒,如果上一个节点不存在,则再去获取锁        while ((System.currentTimeMillis() - beginTime) < 5000) {            System.out.println(Thread.currentThread().getName()+" 正在监听节点 " + ROOT_PATH + "/" + key + "/" + beforeNode);            try {                if (zookeeper.exists(ROOT_PATH + "/" + key + "/" + beforeNode, false) == null) {                    return lockHandler(key, beginTime, result);                }            } catch (KeeperException e) {} catch (InterruptedException e) {}            try {                Thread.sleep(500);            } catch (InterruptedException e) {                e.printStackTrace();            }        }        System.out.println(Thread.currentThread().getName()+"之前的节点" + beforeNode + "未释放,放弃获取锁");        try {            zookeeper.delete(ROOT_PATH + "/" + key + "/" + result, -1);        } catch (InterruptedException e) {} catch (KeeperException e) {}        return false;    }    /**     * 删除一个监听对象下所有的节点     * @param key     * @return     */    public static boolean unLockNode(String key){        List<String> list = null;        try {            list = zookeeper.getChildren(ROOT_PATH + "/" + key, false);        } catch (KeeperException e) {  } catch (InterruptedException e) {  }        if (list != null) {            for (String s : list) {                try {                    zookeeper.delete(ROOT_PATH + "/" + key + "/" + s, -1);                } catch (InterruptedException e) {  } catch (KeeperException e) { }            }        }        return true;    }    /**     * 解锁当前获取锁的节点     *     * @param key     * @return     * @throws InterruptedException     * @throws KeeperException     */    public static boolean unLock(String key) {        System.out.println("开始解锁-------------");        List<String> list = null;        try {            list = zookeeper.getChildren(ROOT_PATH + "/" + key, false);        } catch (KeeperException e) {} catch (InterruptedException e) {}        if (list == null || list.size() == 0) {            System.out.println(Thread.currentThread().getName()+"锁不存在,或已经被解锁,成功!");            return false;        }        System.out.println("==========================================");        list.sort(new Comparator<String>() {            @Override            public int compare(String o1, String o2) {                return Integer.valueOf(o1) - Integer.valueOf(o2);            }        });        try {            zookeeper.delete(ROOT_PATH + "/" + key + "/" + list.get(0), -1);        } catch (InterruptedException e) {} catch (KeeperException e) {}        try {            if (zookeeper.exists(ROOT_PATH + "/" + key + "/" + list.get(0), false) != null) {                System.out.println(Thread.currentThread().getName()+" 解锁失败!");                return false;            }        } catch (KeeperException e) {} catch (InterruptedException e) {}        System.out.println(Thread.currentThread().getName()+" 解锁成功!");        return true;    }    public static void main(String[] args) {//        System.out.println(LockUtil.getLock("a1"));//        System.out.println(LockUtil.unLock("a1"));        new Thread() {            @Override            public void run() {                System.out.println(LockUtil.getLock("a1"));                try {                    Thread.sleep(2000);                } catch (InterruptedException e) {                    e.printStackTrace();                }                System.out.println(LockUtil.unLock("a1"));        }}.start();        new Thread() {            @Override            public void run() {                    System.out.println(LockUtil.getLock("a1"));                    System.out.println(LockUtil.unLock("a1"));        }}.start();        new Thread() {            @Override            public void run() {                System.out.println(LockUtil.getLock("a1"));            }}.start();        LockUtil.unLockNode("a1");    }}

运行

==============================================================================================================================Thread-2获取锁结果: 0000000301 :0000000300Thread-0获取锁结果: 0000000300 :0000000300Thread-1获取锁结果: 0000000302 :0000000300Thread-0/lockdata/a1 获取锁成功Thread-2 正在监听节点 /lockdata/a1/0000000300trueThread-1 正在监听节点 /lockdata/a1/0000000301Thread-2 正在监听节点 /lockdata/a1/0000000300Thread-1 正在监听节点 /lockdata/a1/0000000301Thread-2 正在监听节点 /lockdata/a1/0000000300Thread-1 正在监听节点 /lockdata/a1/0000000301Thread-2 正在监听节点 /lockdata/a1/0000000300Thread-1 正在监听节点 /lockdata/a1/0000000301开始解锁-------------==========================================Thread-0 解锁成功!trueThread-2 正在监听节点 /lockdata/a1/0000000300==========================================Thread-2获取锁结果: 0000000301 :0000000301Thread-2/lockdata/a1 获取锁成功trueThread-1 正在监听节点 /lockdata/a1/0000000301Thread-1 正在监听节点 /lockdata/a1/0000000301Thread-1 正在监听节点 /lockdata/a1/0000000301Thread-1 正在监听节点 /lockdata/a1/0000000301Thread-1 正在监听节点 /lockdata/a1/0000000301Thread-1 正在监听节点 /lockdata/a1/0000000301Thread-1之前的节点0000000301未释放,放弃获取锁false

使用zookeeper相对使用redis作为分布式锁的区别

优势 缺点 zook可作读写锁.(实现方式:使用读写两种方式,获取读锁时当获取的节点前面有比自己小的写锁节点存在,有则获取失败.获取写锁则必须当前节点为最小的节点) 在实现过程中可以看出,效率没有redis的高,固应对高并发能量没有使用redis做分布式锁强
原创粉丝点击