分布式锁:Zookeeper实现分布式锁

分布式锁


最近一段时间统一整理一下分布式锁的实现方法。

zookeeper的方式

原理

使用zookeeper(以下称为zk)实现分布式锁主要是因为,使用了zk节点操作的原子性。
如下:

https://zookeeper.apache.org/doc/r3.5.7/zookeeperOver.html
zk文档
The data stored at each znode in a namespace is read and written atomically. Reads get all the data bytes associated with a znode and a write replaces all the data. Each node has an Access Control List (ACL) that restricts who can do what.
Atomicity - Updates either succeed or fail. No partial results.

ps:也是通过翻译看的。。。至于zk的其他东西,在这不详细说了,只是说说基本的使用。有时间整理一套zk的内容。下面直接上代码。

Java代码

1.首先,你需要有一个zk。如何安装zk,自行百度。
2.演示一下,没有分布式锁的情况下的代码(这里一生成一个唯一id为业务场景)。

package com.peter;

/**
 * 业务场景
 * @author Peter
 */
public class Main {
    //模拟id
    public static int ID = 0;

    public static void main(String[] args) {
        System.out.println("####生成唯一ID####");
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                ID++;
                System.out.println("当前线程:" + Thread.currentThread().getName() + ";当前id:" + ID);
            }).start();
        }


    }
}

输出结果

####生成唯一ID####
当前线程:Thread-0;当前id:2
当前线程:Thread-2;当前id:3
当前线程:Thread-3;当前id:4
当前线程:Thread-1;当前id:2
当前线程:Thread-4;当前id:5
当前线程:Thread-5;当前id:6
当前线程:Thread-6;当前id:7
当前线程:Thread-7;当前id:9
当前线程:Thread-8;当前id:8
当前线程:Thread-9;当前id:10

出现了id重复的情况,接下来使用zk进行处理

3.zk锁代码
3.1 ZkAbstractLock

package com.peter.zk;

import org.I0Itec.zkclient.ZkClient;

import java.util.concurrent.locks.Lock;

/**
 * 抽象zk分布式锁
 *
 * @author Peter
 */
public abstract class ZkAbstractLock implements Lock {
    // zk连接地址
    private static final String ZK_ADDRESS = "127.0.0.1:2181";
    // 创建zk连接
    protected ZkClient zkClient = new ZkClient(ZK_ADDRESS);
    protected static final String PATH = "/peterlock";


    public void lock() {
        if (tryLock()) {
            System.out.println("####线程:" + Thread.currentThread().getId() + ",获取lock####");
        } else {
            waitLock();
            lock();
        }

    }

    public void unlock() {
        if (zkClient != null) {
            zkClient.close();
            System.out.println("&&&&线程:" + Thread.currentThread().getId() + ",释放锁资源&&&&");
        }
    }

    protected abstract void waitLock();


}

3.2 ZkDistributLock

package com.peter.zk;

import org.I0Itec.zkclient.IZkDataListener;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;

/**
 * zk分布式锁
 *
 * @author Peter
 * @date 2020-03-07 15:46
 */
public class ZkDistributLock extends ZkAbstractLock {
    private CountDownLatch countDownLatch = null;

    protected void waitLock() {
        IZkDataListener izkDataListener = new IZkDataListener() {

            public void handleDataDeleted(String path) {
                // 唤醒被等待的线程
                if (countDownLatch != null) {
                    countDownLatch.countDown();
                }
            }

            public void handleDataChange(String path, Object data) {

            }
        };
        // 注册事件
        zkClient.subscribeDataChanges(PATH, izkDataListener);
        if (zkClient.exists(PATH)) {
            countDownLatch = new CountDownLatch(1);
            try {
                countDownLatch.await();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        // 删除监听
        zkClient.unsubscribeDataChanges(PATH, izkDataListener);

    }


    public boolean tryLock() {
        try {
            zkClient.createEphemeral(PATH);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

    }

    public boolean tryLock(long time, TimeUnit unit) {
        return false;
    }

    public Condition newCondition() {
        return null;
    }

    public void lockInterruptibly() {

    }
}

3.3

package com.peter;

import com.peter.zk.ZkDistributLock;

import java.util.concurrent.locks.Lock;

/**
 * 业务场景
 *
 * @author Peter
 * @date 2020-03-07 15:01
 */
public class Main {
    //模拟id
    public static int ID = 0;


    public static void main(String[] args) {
        System.out.println("####生成唯一ID####");
        for (int i = 0; i < 30; i++) {
            new Thread(() -> {
                Lock lock = new ZkDistributLock();
                try {
                	lock.lock();
                    Thread.sleep(100);
                    ID++;
               		lock.unlock();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
               
                System.out.println("当前线程:" + Thread.currentThread().getName() + ";当前id:" + ID);
            }).start();
        }


    }
}

输出结果:

####线程:35,获取lock####
&&&&线程:35,释放锁资源&&&&
当前线程:Thread-23;当前id:1
####线程:23,获取lock####
&&&&线程:23,释放锁资源&&&&
当前线程:Thread-11;当前id:2
####线程:37,获取lock####
&&&&线程:37,释放锁资源&&&&
当前线程:Thread-25;当前id:3
####线程:33,获取lock####
&&&&线程:33,释放锁资源&&&&
当前线程:Thread-21;当前id:4
####线程:28,获取lock####
&&&&线程:28,释放锁资源&&&&
当前线程:Thread-16;当前id:5
####线程:29,获取lock####
&&&&线程:29,释放锁资源&&&&
当前线程:Thread-17;当前id:6
####线程:13,获取lock####
&&&&线程:13,释放锁资源&&&&
当前线程:Thread-1;当前id:7
####线程:39,获取lock####
&&&&线程:39,释放锁资源&&&&
当前线程:Thread-27;当前id:8
####线程:41,获取lock####
&&&&线程:41,释放锁资源&&&&
当前线程:Thread-29;当前id:9
####线程:27,获取lock####
&&&&线程:27,释放锁资源&&&&
当前线程:Thread-15;当前id:10
####线程:14,获取lock####
&&&&线程:14,释放锁资源&&&&
当前线程:Thread-2;当前id:11
####线程:38,获取lock####
&&&&线程:38,释放锁资源&&&&
当前线程:Thread-26;当前id:12
####线程:22,获取lock####
&&&&线程:22,释放锁资源&&&&
当前线程:Thread-10;当前id:13
####线程:32,获取lock####
&&&&线程:32,释放锁资源&&&&
当前线程:Thread-20;当前id:14
####线程:31,获取lock####
&&&&线程:31,释放锁资源&&&&
当前线程:Thread-19;当前id:15
####线程:30,获取lock####
&&&&线程:30,释放锁资源&&&&
当前线程:Thread-18;当前id:16
####线程:17,获取lock####
&&&&线程:17,释放锁资源&&&&
当前线程:Thread-5;当前id:17
####线程:34,获取lock####
&&&&线程:34,释放锁资源&&&&
当前线程:Thread-22;当前id:18
####线程:19,获取lock####
&&&&线程:19,释放锁资源&&&&
当前线程:Thread-7;当前id:19
####线程:40,获取lock####
&&&&线程:40,释放锁资源&&&&
当前线程:Thread-28;当前id:20
####线程:15,获取lock####
&&&&线程:15,释放锁资源&&&&
当前线程:Thread-3;当前id:21
####线程:26,获取lock####
&&&&线程:26,释放锁资源&&&&
当前线程:Thread-14;当前id:22
####线程:16,获取lock####
&&&&线程:16,释放锁资源&&&&
当前线程:Thread-4;当前id:23
####线程:20,获取lock####
&&&&线程:20,释放锁资源&&&&
当前线程:Thread-8;当前id:24
####线程:21,获取lock####
&&&&线程:21,释放锁资源&&&&
当前线程:Thread-9;当前id:25
####线程:25,获取lock####
&&&&线程:25,释放锁资源&&&&
当前线程:Thread-13;当前id:26
####线程:12,获取lock####
&&&&线程:12,释放锁资源&&&&
当前线程:Thread-0;当前id:27
####线程:36,获取lock####
&&&&线程:36,释放锁资源&&&&
当前线程:Thread-24;当前id:28
####线程:24,获取lock####
&&&&线程:24,释放锁资源&&&&
当前线程:Thread-12;当前id:29
####线程:18,获取lock####
&&&&线程:18,释放锁资源&&&&
当前线程:Thread-6;当前id:30

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值