<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
如果有一把锁,被多个人给竞争,此时多个人会排队,第一个拿到锁的人会执行,然后释放锁;后面的每个人都会去监听**排在自己前面**的那个人创建的 node 上,一旦某个人释放了锁,排在自己后面的人就会被 zookeeper 给通知,一旦被通知了之后,就 ok 了,自己就获取到了锁,就可以执行代码了。
```java
public class ZooKeeperDistributedLock {
//private ZooKeeper zk;
private ZkClient zk;
private String locksRoot = "/locks";
private String productId;
private String waitNode;
private String lockNode;
private CountDownLatch latch;
private int sessionTimeout = 30000;
public ZooKeeperDistributedLock() {
try {
String address="192.168.31.187:2181,192.168.31.19:2181,192.168.31.227:2181";
zk = new ZkClient(address, sessionTimeout, sessionTimeout);
} catch (IOException e) {
throw new LockException(e);
} catch (KeeperException e) {
throw new LockException(e);
} catch (InterruptedException e) {
throw new LockException(e);
}
}
public void acquireDistributedLock() {
try {
if (this.tryLock()) {
return;
} else {
waitForLock(waitNode, sessionTimeout);
acquireDistributedLock();
}
} catch (KeeperException e) {
throw new LockException(e);
} catch (InterruptedException e) {
throw new LockException(e);
}
}
public boolean tryLock() {
try {
lockNode = this.client.createEphemeralSequential(locksRoot+ "/", "1");
// 看看刚创建的节点是不是最小的节点
// locks:10000000000,10000000001,10000000002
List<String> locks = zk.getChildren(locksRoot);
Collections.sort(locks);
if(lockNode.equals(locksRoot+"/"+ locks.get(0))){
System.out.println(Thread.currentThread().getName() + ":获取锁成功");
//如果是最小的节点,则表示取得锁
return true;
}
//如果不是最小的节点,找到比自己小1的节点
int previousLockIndex = -1;
for(int i = 0; i < locks.size(); i++) {
if(lockNode.equals(locksRoot + “/” + locks.get(i))) {
previousLockIndex = i - 1;
break;
}
}
this.waitNode = locks.get(previousLockIndex);
} catch (KeeperException e) {
throw new LockException(e);
} catch (InterruptedException e) {
throw new LockException(e);
}
return false;
}
private boolean waitForLock(String waitNode, long waitTime) throws
InterruptedException, KeeperException {
Stat stat = zk.exists(locksRoot + "/" + waitNode, true);
this.latch = new CountDownLatch(1);
IZkDataListener listener = new IZkDataListener() {
@Override
public void handleDataChange(String arg0, Object arg1) throws Exception {
}
@Override
public void handleDataDeleted(String arg0)
throws Exception {
System.out.println("节点被删除了,开始抢锁");
cdl.countDown();
}
};
// 完成watcher注册
this.client.subscribeDataChanges(beforePath, listener);
if (stat != null) {
this.latch.await(waitTime, TimeUnit.MILLISECONDS);
this.latch = null;
}
// 取消注册
this.client.unsubscribeDataChanges(beforePath, listener);
return true;
}
public void unlock() {
try {
// 删除/locks/10000000000节点
// 删除/locks/10000000001节点
System.out.println("unlock " + lockNode);
zk.delete(lockNode);
System.out.println(Thread.currentThread().getName()
+ "所有锁释放成功:删除zk节点");
lockNode = null;
zk.close();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (KeeperException e) {
e.printStackTrace();
}
}
public class LockException extends RuntimeException {
private static final long serialVersionUID = 1L;
public LockException(String e) {
super(e);
}
public LockException(Exception e) {
super(e);
}
}
}
public class OrderCodeGenerator {
private int i = 0;
public String getOrderCode() {
Date now = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-");
return sdf.format(now) + ++i;
}
}
public class OrderServiceImplWithZkDis implements OrderService {
private static OrderCodeGenerator org = new OrderCodeGenerator();
private Lock lock = new ZooKeeperDistributedLock();
@Override
public void createOrder() {
String orderCode = null;
try {
lock.acquireDistributedLock();
orderCode = org.getOrderCode();
//TestReLock();
System.out.println(Thread.currentThread().getName() + "生成订单:" + orderCode);
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
/**
public void TestReLock() {
lock.acquireDistributedLock();
System.out.println(Thread.currentThread().getName() + "测试重入锁成功...");
lock.unlock();
}
**/
public static void main(String[] args) {
int num = 5;
CyclicBarrier cyclicBarrier = new CyclicBarrier(num);
for (int i = 0; i < num; i++) {
new Thread(new Runnable() {
@Override
public void run() {
OrderService orderService = new OrderServiceImplWithZkDis();
System.out.println(Thread.currentThread().getName() + ": 我准备好了");
try {
cyclicBarrier.await();
} catch (Exception e) {
e.printStackTrace();
}
orderService.createOrder();
}
}).start();
}
}
}
Thread-2:我准备好了
Thread-3:我准备好了
Thread-1:我准备好了
Thread-5:我准备好了
Thread-4:我准备好了
Thread-4:获取锁成功
Thread-4生成订单:2018-07-12-13-12-09-1
Thread-4所有锁释放成功:删除ZK节点
节点删除了,开始抢锁
Thread-5:获取锁成功
Thread-5生成订单:2018-07-12-13-12-11-2
Thread-5所有锁释放成功:删除ZK节点
节点删除了,开始抢锁
Thread-2:获取锁成功
Thread-2生成订单:2018-07-12-13-12-14-3
Thread-2所有锁释放成功:删除ZK节点
节点删除了,开始抢锁
Thread-3:获取锁成功
Thread-3生成订单:2018-07-12-13-12-17-4
Thread-3所有锁释放成功:删除ZK节点
节点删除了,开始抢锁
Thread-1:获取锁成功
Thread-1生成订单:2018-07-12-13-12-21-5
Thread-1所有锁释放成功:删除ZK节点
节点删除了,开始抢锁