zookeeper实现分布式锁

通过用zk创建临时节点的特性,实现分布式锁;
当前只有一个线程创建成功,然后close之后,该节点被删除;
其他线程可以再次争抢。

实现一个生成订单号,几个线程生成几个订单号,模仿多jvm对应多个线程

public class OrderNumCreateUtil {

	private static int number = 0;
	public String getOrderNumber(){
		return "	 生成订单号:" + (++ number);
	}
}
public interface ZkLock {

	public void zklock();
	public void zkUnlock();
}

利用模板方法模式,把需要经常改的东西抽象出来,交给子类去实现

public abstract class ZkAbstractLock implements ZkLock{
	
	public static final String ZKSERVER = "47.100.41.55:2181";
	public static final int TIME_OUT = 45 * 1000;
	ZkClient zkClient = new ZkClient(ZKSERVER, TIME_OUT);
	
	protected String path = "/zklock0401";
	protected CountDownLatch countDownLatch = null;
	
	@Override
	public void zklock() {
		if(tryZkLock()){
			System.out.println(Thread.currentThread().getName() + "	 占用锁成功。");
		}else{
			waitZkLock();
			zklock();
		}
	}

	public abstract  void waitZkLock();

	public abstract boolean tryZkLock();

	@Override
	public void zkUnlock() {
		if(zkClient != null){
			zkClient.close();
		}
		System.out.println(Thread.currentThread().getName() + "	 释放锁成功。");
		System.out.println();
		System.out.println();
	}
}
public class ZkDistributedLock extends ZkAbstractLock{

	@Override
	public void waitZkLock() {
		//监听path,1,数据是否改变或删除
		IZkDataListener iZkDataListener = new IZkDataListener() {
			
			@Override
			public void handleDataDeleted(String arg0) throws Exception {
				if(countDownLatch != null){
					countDownLatch.countDown();
				}
			}
			
			@Override
			public void handleDataChange(String arg0, Object arg1) throws Exception {
				
			}
		};
		zkClient.subscribeDataChanges(path, iZkDataListener);
		if(zkClient.exists(path)){
			//只能等着,因为锁已经被其他线程占领了
			countDownLatch = new CountDownLatch(1);
			try {
				countDownLatch.await();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		zkClient.unsubscribeDataChanges(path, iZkDataListener);
	}

	@Override
	public boolean tryZkLock() {
		try {
			//创建临时节点
			zkClient.createEphemeral(path);
			return true;
		} catch (Exception e) {
			return false;
		}
	}
}
public class OrderService {

	private OrderNumCreateUtil orderNumCreateUtil = new OrderNumCreateUtil();
	private ZkLock zklock = new ZkDistributedLock();
	
	public void getOrderNum(){
		zklock.zklock();
		try {
			System.out.println("获得编号:----->:" + orderNumCreateUtil.getOrderNumber());
		} catch (Exception e) {
			
		}finally{
			zklock.zkUnlock();
		}
	}
}
public class Client {
	public static void main(String[] args) {
		for (int i = 0; i < 20; i++) {
			new Thread(()->{
				//模仿多jvm
				new OrderService().getOrderNum();
			},String.valueOf(i)).start();
		}
	}
}

输出:

19	 占用锁成功。
获得编号:----->:	 生成订单号:1
19	 释放锁成功。


12	 占用锁成功。
获得编号:----->:	 生成订单号:2
12	 释放锁成功。


9	 占用锁成功。
获得编号:----->:	 生成订单号:3
9	 释放锁成功。


7	 占用锁成功。
获得编号:----->:	 生成订单号:4
0	 占用锁成功。
获得编号:----->:	 生成订单号:5
7	 释放锁成功。


0	 释放锁成功。


17	 占用锁成功。
获得编号:----->:	 生成订单号:6
17	 释放锁成功。 


4	 占用锁成功。
获得编号:----->:	 生成订单号:7
4	 释放锁成功。


6	 占用锁成功。
获得编号:----->:	 生成订单号:8
6	 释放锁成功。


14	 占用锁成功。
获得编号:----->:	 生成订单号:9
14	 释放锁成功。


11	 占用锁成功。
获得编号:----->:	 生成订单号:10
11	 释放锁成功。


10	 占用锁成功。
获得编号:----->:	 生成订单号:11
10	 释放锁成功。


2	 占用锁成功。
获得编号:----->:	 生成订单号:12
2	 释放锁成功。


18	 占用锁成功。
获得编号:----->:	 生成订单号:13
18	 释放锁成功。


15	 占用锁成功。
获得编号:----->:	 生成订单号:14
15	 释放锁成功。


13	 占用锁成功。
获得编号:----->:	 生成订单号:15
13	 释放锁成功。


8	 占用锁成功。
获得编号:----->:	 生成订单号:16
8	 释放锁成功。


16	 占用锁成功。
获得编号:----->:	 生成订单号:17
16	 释放锁成功。


5	 占用锁成功。
获得编号:----->:	 生成订单号:18
5	 释放锁成功。


3	 占用锁成功。
获得编号:----->:	 生成订单号:19
3	 释放锁成功。


1	 占用锁成功。
获得编号:----->:	 生成订单号:20
1	 释放锁成功。
原文地址:https://www.cnblogs.com/kaka-qiqi/p/14927439.html