<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 ZookeeperReAbleDisLock("/LOCK_TEST");
@Override
public void createOrder() {
String orderCode = null;
try {
lock.lock();
orderCode = org.getOrderCode();
//TestReLock();
System.out.println(Thread.currentThread().getName() + "生成訂單:" + orderCode);
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
/**
public void TestReLock() {
lock.lock();
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節點
節點刪除了,開始搶鎖