基于zookeeper实现分布式锁

分布式锁作用及其原理

  • 为什么要有分布式锁
    分布式服务中,如果各个服务节点需要去竞争资源,没办法使用单机多线程中JDK自带的锁,故此时需要分布式锁来协调。
  • 有哪些常见的手段来实现分布式锁
    zookeeper、redis、memcache
  • 分布式锁的原理
    zookeeper:去创建相应的节点,创建成功,则表示获取到相应的锁,创建失败,则表示获取锁失败
    redis、memcache:对应的去设置一个值做为锁的一标志,每次获取锁的时候,判断对应的值是否存在,存在则无法获取,不存在,则设置相应的值,表示获取到锁。(redis 使用setnx,memcache使用add)

实现分布式锁

  • 引入依赖
<dependency>
    <groupId>org.apache.zookeeper</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.4.13</version>
</dependency>
  • 代码实现
public class ZkLock {

    private ZooKeeper zooKeeper;

    private static CountDownLatch countDownLatch = new CountDownLatch(1);

    public ZkLock() {
        try {
            zooKeeper = new ZooKeeper("120.25.2.123:2181,120.25.2.123:2182,120.25.2.123:2183",
                    5000,new ZkWatcher());
            System.out.println(zooKeeper.getState());
            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("与zk建立连接=====>"+zooKeeper.getState());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static ZkLock getInstance() {
        return Singleton.getInstance();
    }

    private class ZkWatcher implements Watcher {

        @Override
        public void process(WatchedEvent watchedEvent) {
            System.out.println("接收到监听事件=====>"+watchedEvent);
            if (Event.KeeperState.SyncConnected == watchedEvent.getState()) {
                countDownLatch.countDown();
            }
        }
    }

    public void lock(Integer id) {
        String path = "/jiangchh-product-lock-" + id;
        //创建临时节点,如果创建成功,则表示获取锁,如果失败,则不断尝试
        try {
            zooKeeper.create(path,"".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
            System.out.println("成功获取到锁");
        } catch (Exception e) {
            while (true) {
                try {
                    Thread.sleep(500L);
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }
                try {
                    zooKeeper.create(path,"".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
                } catch (Exception ex) {
                    continue;
                }
                break;
            }
        }
    }

    /**
     * 释放锁
     * @param id
     */
    public void unLock(Integer id) {
        String path = "/jiangchh-product-lock-" + id;
        try {
            zooKeeper.delete(path,-1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (KeeperException e) {
            e.printStackTrace();
        }
    }

    private static class Singleton {

        private static ZkLock instance;
        static {
            instance = new ZkLock();
        }

        private static ZkLock getInstance() {
            return instance;
        }
    }

}

测试

public class ZkLockTest {

    private static int num = 0;

    private static CountDownLatch countDownLatch = new CountDownLatch(10);
    private static ZkLock lock = ZkLock.getInstance();

    /**
     * 每次调用对num进行++操作
     */
    public static void inCreate() {
        lock.lock(1);
        num++;
        System.out.println(num);
        lock.unLock(1);
    }

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                for (int j = 0; j < 100; j++) {
                    inCreate();
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //每个线程执行完成之后,调用countdownLatch
                countDownLatch.countDown();
            }).start();
        }

        while (true) {
            if (countDownLatch.getCount() == 0) {
                System.out.println(num);
                break;
            }
        }
    }
}

注意事项

I、创建节点的时候,一定要创建临时节点,避免应用获取到锁后,宕机,导致锁一致被持有
II、原生api不支持递归创建节点
III、如果是单一应用,尽量不要使用分布式锁,比较耗性能

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值