java实现zookeeper分布式锁

基本思路

1 client调用create()方法创建“/locks/lock”临时顺序节点,注意节点类型是EPHEMERAL_SEQUENTIAL

2 client调用getChildren("/locks",false)来获取所有已经创建的子节点,这里并不注册任何Watcher,只是为了看自己的是不是最小的节点

如果是,便获得了锁。

3 客户端获取到所有子节点Path后,如果发现自己在步骤1中创建的节点是所有节点中最小的,那么就认为这个客户端获得了锁 执行

4 如果在步骤3中,发现不是最小的,那么找到比自己小的那个节点,然后对其调用exist()方法注册事件监听,通过计数器阻塞

5 之后一旦这个被关注的节点移除,客户端会收到相应的通知,计数器countdown 不在阻塞 继续执行

代码如下:

public class MydistributedLock implements Watcher, Lock {
	private ZooKeeper zk = null;
	private String rootLockName = "/locks";
	// zk connect counter
	private CountDownLatch zkConnectCountDouwnLatch = new CountDownLatch(1);
	// zk wait lock counter
	private CountDownLatch waitCountDownLatch;
	// current node name
	private String curName;
	// the node which current node is listening
	private String waitName;
	// competing resource
	private String lockName;
	private int zkTimeOut = 30000;

	public MydistributedLock(String connectUrl, String lockName) throws Exception {
		try {
			zk = new ZooKeeper(connectUrl, zkTimeOut, this);
			this.lockName = lockName;
			zkConnectCountDouwnLatch.await();
			Stat stat = zk.exists(rootLockName, false);
			if (stat == null) {
				zk.create(rootLockName, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
			}

		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	public void process(WatchedEvent event) {
		org.apache.zookeeper.Watcher.Event.EventType eventType = event.getType();
		if (eventType == org.apache.zookeeper.Watcher.Event.EventType.NodeDeleted) {
			// if node is not exist,don't wait it
			if (this.waitCountDownLatch != null) {
				this.waitCountDownLatch.countDown();
			}
			// connection is success
			else if (eventType == org.apache.zookeeper.Watcher.Event.EventType.None)
				zkConnectCountDouwnLatch.countDown();
		}

	}

	public void lock() {
		if (tryLock()) {
			return;
		} else {
			waitForLock();
		}

	}

	private void waitForLock() {
		try {
			Stat stat = zk.exists(rootLockName + "/" + waitName, true);
			if (stat != null) {
				this.waitCountDownLatch = new CountDownLatch(1);
				this.waitCountDownLatch.await();
				this.waitCountDownLatch = null;
				System.out.println(Thread.currentThread().getName() + "等到了lock");
			}
		} catch (KeeperException e) {

			e.printStackTrace();
		} catch (InterruptedException e) {

			e.printStackTrace();
		}

	}

	public void lockInterruptibly() throws InterruptedException {
		// TODO Auto-generated method stub

	}

	public boolean tryLock() {
		try {
			curName = zk.create(rootLockName + "/" + lockName + "_lock_", new byte[0], Ids.OPEN_ACL_UNSAFE,
					CreateMode.PERSISTENT_SEQUENTIAL);
			List<String> subNodes = zk.getChildren(rootLockName, false);
			Collections.sort(subNodes);
			// get all the children nodes compared with current node to judge it if is the
			// smallest
			if (curName.equals(rootLockName + "/" + subNodes.get(0))) {
				return true;
			}
			int curIndex = subNodes.indexOf(curName.split("/")[2]);
			// if the current node is not the smallest,find the one in front
			waitName = subNodes.get(curIndex - 1);
		} catch (KeeperException e) {

			e.printStackTrace();
		} catch (InterruptedException e) {

			e.printStackTrace();
		}
		return false;
	}

	public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
		// TODO Auto-generated method stub
		return false;
	}

	public void unlock() {
		System.out.println(Thread.currentThread().getName() + "unlock");
		try {
			zk.delete(curName, -1);
			curName = null;
			zk.close();
		} catch (InterruptedException e) {

			e.printStackTrace();
		} catch (KeeperException e) {

			e.printStackTrace();
		}

	}

	public Condition newCondition() {
		// TODO Auto-generated method stub
		return null;
	}
}

测试代码:

public class TestLock {
	static int n = 0;

	public static void add() {
		System.out.println(++n);
	}

	public static void main(String[] args) {
		Runnable runnable = new Runnable() {

			public void run() {
				MydistributedLock lock = null;
				try {
					lock = new MydistributedLock("192.168.1.200:2081", "test");
					lock.lock();
					add();
					System.out.println(Thread.currentThread().getName() + "is running");
				} catch (Exception e) {

					e.printStackTrace();
				} finally {
					if (lock != null) {
						lock.unlock();
					}
				}

			}

		};
		ExecutorService executor = Executors.newCachedThreadPool();
		for (int i = 0; i < 10; i++) {
			executor.submit(runnable);
		}
		executor.shutdown();
	}
}

运行结果如下:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值