ZooKeeper实现分布式锁(一)

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能够保证分布式环境下只有一个线程获取锁,并且也能成功释放锁,这次先分享到这里,下回将分享如何对锁进行监控,在持有锁的线程释放后,其他的线程能得到通知重新竞争锁。

你可能感兴趣的:(ZooKeeper)