ZooKeeper实现分布式锁(一)

本文介绍使用ZooKeeper实现分布式锁的方法,包括创建和删除节点的过程,通过示例代码展示了如何在一个路径下建立子节点并实现分布式锁,确保并发环境下的唯一性和一致性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ZooKeeper可以在其目录下建立节点,这些节点都是以路径和值为映射关系存在的,下面通过一个例子说明如何创建节点和删除节点。
public class TestLock {

	public static void main(String[] args) {
		ZkClient zkClient1 = new ZkClient(new ZkConnection("127.0.0.1:2181"), 10000);
		String path = "/exclusive_lock";
		if(!zkClient1.exists(path)) {
			zkClient1.createPersistent(path, "root");
		} else {
			System.out.println("/exclusive_lock 路径已经存在, 开始删除");
			zkClient1.delete("/exclusive_lock");
			System.out.println("/exclusive_lock 路径已经存在, 删除成功");
		}
		
		if(zkClient1.exists("/exclusive_lock")) {
			System.out.println("/exclusive_lock 路径已经存在");
		} else {
			System.out.println("/exclusive_lock 路径不存在");
		}
        }
}

第一次执行结果是
/exclusive_lock 路径已经存在

第二次执行结果是
/exclusive_lock 路径已经存在, 开始删除
/exclusive_lock 路径已经存在, 删除成功
/exclusive_lock 路径不存在

在节点下还可以建立子节点,如果节点下有子节点需要删除,需要用到级联删除。
zkClient1.deleteRecursive("/exclusive_lock");

利用zookeeper的这个特性,我们可以实现分布式锁,保证高并发环境下CAP中的CP特性。

先实现一个简化版的分布式锁,只有加锁和释放锁两个方法。    

public class DistributedLock {
	
	public boolean tryLock(ZkClient zkClient, String path, String value) {
		try {
			zkClient.createPersistent(path, value);
			
		} catch (Exception e) {
			
			return false;
		}
		
		return true;
	}
	
	public void releaseLock(ZkClient zkClient, String path) {
		zkClient.deleteRecursive(path);
	}
}

写一个线程任务,方便后面做并发测试。

@Getter
@Setter
public class Task implements Runnable {
	private String path;
	
	private String value;
	
	private ZkClient zkClient;
	
	public Task(ZkClient zkClient, String path, String value) {
		this.zkClient = zkClient;
		this.path = path;
		this.value = value;
	}
	
	public void run() {
		DistributedLock distributedLock = new DistributedLock();
		if(distributedLock.tryLock(zkClient, path, value)){
			System.out.println(Thread.currentThread().getName()+"加锁成功, 开始做任务了");
			try {
				Thread.currentThread().sleep(10000L);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName()+"做了一段时间任务,完成了开始释放锁");
			distributedLock.releaseLock(zkClient, path);
		} else {
			System.out.println(Thread.currentThread().getName()+"加锁失败, 休息一下吧");
			try {
				Thread.currentThread().sleep(10000L);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}


}

继续在前面的测试锁的类中进行测试,这里前提条件是已经建好了exclusive_lock 这个path,然后需要在这个path下建立lock子路径,通过多个线程同时并发创建,看是否能保证只建立唯一的lock子路径。

public static void main(String[] args) {
	ZkClient zkClient1 = new ZkClient(new ZkConnection("127.0.0.1:2181"), 10000);
	String path = "/exclusive_lock";
	zkClient1.createPersistent(path, "root");
	ExecutorService executorService = Executors.newFixedThreadPool(2);
	for(int i=0; i<2; i++){
	     executorService.submit(new Task(zkClient1, "/exclusive_lock/lock", "lock"));
	} }

跑出的结果:

pool-1-thread-2加锁成功, 开始做任务了
pool-1-thread-1加锁失败, 休息一下吧
pool-1-thread-2做了一段时间任务,完成了开始释放锁
从执行结果来看,zookeeper能够保证分布式环境下只有一个线程获取锁,并且也能成功释放锁,这次先分享到这里,下回将分享如何对锁进行监控,在持有锁的线程释放后,其他的线程能得到通知重新竞争锁。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值