ZooKeeper是一個分布式的,開放源碼的分布式應用程序協調服務,是Google的Chubby一個開源的實現,是Hadoop和Hbase的重要組件。它是一個為分布式應用提供一致性服務的軟件,提供的功能包括:配置維護、域名服務、分布式同步、組服務等。
ZooKeeper的架構通過冗余服務實現高可用性。因此,如果第一次無應答,客戶端就可以詢問另一臺ZooKeeper主機。ZooKeeper節點將它們的數據存儲于一個分層的命名空間,非常類似于一個文件系統或一個前綴樹結構。客戶端可以在節點讀寫,從而以這種方式擁有一個共享的配置服務。更新是全序的。
基于ZooKeeper分布式鎖的流程
在zookeeper指定節點(locks)下創建臨時順序節點node_n
獲取locks下所有子節點children
對子節點按節點自增序號從小到大排序
判斷本節點是不是第一個子節點,若是,則獲取鎖;若不是,則監聽比該節點小的那個節點的刪除事件
若監聽事件生效,則回到第二步重新進行判斷,直到獲取到鎖
具體實現
下面就具體使用java和zookeeper實現分布式鎖,操作zookeeper使用的是apache提供的zookeeper的包。
通過實現Watch接口,實現process(WatchedEvent event)方法來實施監控,使CountDownLatch來完成監控,在等待鎖的時候使用CountDownLatch來計數,等到后進行countDown,停止等待,繼續運行。
以下整體流程基本與上述描述流程一致,只是在監聽的時候使用的是CountDownLatch來監聽前一個節點。
下邊來看簡單的實現源碼,不用在乎代碼的質量,這里只是簡單地做個演示!!!
分布式鎖:
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
/**
* Created by liuyang on 2017/4/20.
*/
public class DistributedLock implements Lock, Watcher {
? ? private ZooKeeper zk = null;
? ? // 根節點
? ? private String ROOT_LOCK = "/locks";
? ? // 競爭的資源
? ? private String lockName;
? ? // 等待的前一個鎖
? ? private String WAIT_LOCK;
? ? // 當前鎖
? ? private String CURRENT_LOCK;
? ? // 計數器
? ? private CountDownLatch countDownLatch;
? ? private int sessionTimeout = 30000;
? ? private List<Exception> exceptionList = new ArrayList<Exception>();
? ? /**
? ? * 配置分布式鎖
? ? * @param config 連接的url
? ? * @param lockName 競爭資源
? ? */
? ? public DistributedLock(String config, String lockName) {
? ? ? ? this.lockName = lockName;
? ? ? ? try {
? ? ? ? ? ? // 連接zookeeper
? ? ? ? ? ? zk = new ZooKeeper(config, sessionTimeout, this);
? ? ? ? ? ? Stat stat = zk.exists(ROOT_LOCK, false);
? ? ? ? ? ? if (stat == null) {
? ? ? ? ? ? ? ? // 如果根節點不存在,則創建根節點
? ? ? ? ? ? ? ? zk.create(ROOT_LOCK, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
? ? ? ? ? ? }
? ? ? ? } catch (IOException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? } catch (KeeperException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }
? ? }
? ? // 節點監視器
? ? public void process(WatchedEvent event) {
? ? ? ? if (this.countDownLatch != null) {
? ? ? ? ? ? this.countDownLatch.countDown();
? ? ? ? }
? ? }
? ? public void lock() {
? ? ? ? if (exceptionList.size() > 0) {
? ? ? ? ? ? throw new LockException(exceptionList.get(0));
? ? ? ? }
? ? ? ? try {
? ? ? ? ? ? if (this.tryLock()) {
? ? ? ? ? ? ? ? System.out.println(Thread.currentThread().getName() + " " + lockName + "獲得了鎖");
? ? ? ? ? ? ? ? return;
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? // 等待鎖
? ? ? ? ? ? ? ? waitForLock(WAIT_LOCK, sessionTimeout);
? ? ? ? ? ? }
? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? } catch (KeeperException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }
? ? }
? ? public boolean tryLock() {
? ? ? ? try {
? ? ? ? ? ? String splitStr = "_lock_";
? ? ? ? ? ? if (lockName.contains(splitStr)) {
? ? ? ? ? ? ? ? throw new LockException("鎖名有誤");
? ? ? ? ? ? }
? ? ? ? ? ? // 創建臨時有序節點
? ? ? ? ? ? CURRENT_LOCK = zk.create(ROOT_LOCK + "/" + lockName + splitStr, new byte[0],
? ? ? ? ? ? ? ? ? ? ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
? ? ? ? ? ? System.out.println(CURRENT_LOCK + " 已經創建");
? ? ? ? ? ? // 取所有子節點
? ? ? ? ? ? List<String> subNodes = zk.getChildren(ROOT_LOCK, false);
? ? ? ? ? ? // 取出所有lockName的鎖
? ? ? ? ? ? List<String> lockObjects = new ArrayList<String>();
? ? ? ? ? ? for (String node : subNodes) {
? ? ? ? ? ? ? ? String _node = node.split(splitStr)[0];
? ? ? ? ? ? ? ? if (_node.equals(lockName)) {
? ? ? ? ? ? ? ? ? ? lockObjects.add(node);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? Collections.sort(lockObjects);
? ? ? ? ? ? System.out.println(Thread.currentThread().getName() + " 的鎖是 " + CURRENT_LOCK);
? ? ? ? ? ? // 若當前節點為最小節點,則獲取鎖成功
? ? ? ? ? ? if (CURRENT_LOCK.equals(ROOT_LOCK + "/" + lockObjects.get(0))) {
? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? }
? ? ? ? ? ? // 若不是最小節點,則找到自己的前一個節點
? ? ? ? ? ? String prevNode = CURRENT_LOCK.substring(CURRENT_LOCK.lastIndexOf("/") + 1);
? ? ? ? ? ? WAIT_LOCK = lockObjects.get(Collections.binarySearch(lockObjects, prevNode) - 1);
? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? } catch (KeeperException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }
? ? ? ? return false;
? ? }
? ? public boolean tryLock(long timeout, TimeUnit unit) {
? ? ? ? try {
? ? ? ? ? ? if (this.tryLock()) {
? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? }
? ? ? ? ? ? return waitForLock(WAIT_LOCK, timeout);
? ? ? ? } catch (Exception e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }
? ? ? ? return false;
? ? }
? ? // 等待鎖
? ? private boolean waitForLock(String prev, long waitTime) throws KeeperException, InterruptedException {
? ? ? ? Stat stat = zk.exists(ROOT_LOCK + "/" + prev, true);
? ? ? ? if (stat != null) {
? ? ? ? ? ? System.out.println(Thread.currentThread().getName() + "等待鎖 " + ROOT_LOCK + "/" + prev);
? ? ? ? ? ? this.countDownLatch = new CountDownLatch(1);
? ? ? ? ? ? // 計數等待,若等到前一個節點消失,則precess中進行countDown,停止等待,獲取鎖
? ? ? ? ? ? this.countDownLatch.await(waitTime, TimeUnit.MILLISECONDS);
? ? ? ? ? ? this.countDownLatch = null;
? ? ? ? ? ? System.out.println(Thread.currentThread().getName() + " 等到了鎖");
? ? ? ? }
? ? ? ? return true;
? ? }
? ? public void unlock() {
? ? ? ? try {
? ? ? ? ? ? System.out.println("釋放鎖 " + CURRENT_LOCK);
? ? ? ? ? ? zk.delete(CURRENT_LOCK, -1);
? ? ? ? ? ? CURRENT_LOCK = null;
? ? ? ? ? ? zk.close();
? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? } catch (KeeperException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }
? ? }
? ? public Condition newCondition() {
? ? ? ? return null;
? ? }
? ? public void lockInterruptibly() throws InterruptedException {
? ? ? ? this.lock();
? ? }
? ? public class LockException extends RuntimeException {
? ? ? ? private static final long serialVersionUID = 1L;
? ? ? ? public LockException(String e){
? ? ? ? ? ? super(e);
? ? ? ? }
? ? ? ? public LockException(Exception e){
? ? ? ? ? ? super(e);
? ? ? ? }
? ? }
}
入口類:
39?號人?獲取鎖:/locks/test1_lock_0000001385?搶到了第1?件商品;
釋放鎖?/locks/test1_lock_0000001385
35?號人?獲取鎖:/locks/test1_lock_0000001386?搶到了第2?件商品;
釋放鎖?/locks/test1_lock_0000001386
25?號人?獲取鎖:/locks/test1_lock_0000001387?搶到了第3?件商品;
釋放鎖?/locks/test1_lock_0000001387
42?號人?獲取鎖:/locks/test1_lock_0000001388?搶到了第4?件商品;
釋放鎖?/locks/test1_lock_0000001388
19?號人?獲取鎖:/locks/test1_lock_0000001389?搶到了第5?件商品;
釋放鎖?/locks/test1_lock_0000001389
38?號人?獲取鎖:/locks/test1_lock_0000001390?搶到了第6?件商品;
釋放鎖?/locks/test1_lock_0000001390
22?號人?獲取鎖:/locks/test1_lock_0000001391?搶到了第7?件商品;
釋放鎖?/locks/test1_lock_0000001391
18?號人?獲取鎖:/locks/test1_lock_0000001392?搶到了第8?件商品;
釋放鎖?/locks/test1_lock_0000001392
27?號人?獲取鎖:/locks/test1_lock_0000001393?搶到了第9?件商品;
釋放鎖?/locks/test1_lock_0000001393
28?號人?獲取鎖:/locks/test1_lock_0000001394?搶到了第10?件商品;
釋放鎖?/locks/test1_lock_0000001394
2?號人?獲取鎖:/locks/test1_lock_0000001395?搶到了第11?件商品;
釋放鎖?/locks/test1_lock_0000001395
14?號人?獲取鎖:/locks/test1_lock_0000001396?搶到了第12?件商品;
釋放鎖?/locks/test1_lock_0000001396
20?號人?獲取鎖:/locks/test1_lock_0000001397?搶到了第13?件商品;
釋放鎖?/locks/test1_lock_0000001397
11?號人?獲取鎖:/locks/test1_lock_0000001398?搶到了第14?件商品;
釋放鎖?/locks/test1_lock_0000001398
6?號人?獲取鎖:/locks/test1_lock_0000001399?搶到了第15?件商品;
釋放鎖?/locks/test1_lock_0000001399
7?號人?獲取鎖:/locks/test1_lock_0000001400?搶到了第16?件商品;
釋放鎖?/locks/test1_lock_0000001400
29?號人?獲取鎖:/locks/test1_lock_0000001401?搶到了第17?件商品;
釋放鎖?/locks/test1_lock_0000001401
3?號人?獲取鎖:/locks/test1_lock_0000001402?搶到了第18?件商品;
釋放鎖?/locks/test1_lock_0000001402
8?號人?獲取鎖:/locks/test1_lock_0000001403?搶到了第19?件商品;
釋放鎖?/locks/test1_lock_0000001403
32?號人?獲取鎖:/locks/test1_lock_0000001404?搶到了第20?件商品;
釋放鎖?/locks/test1_lock_0000001404
33?號人?獲取鎖:/locks/test1_lock_0000001405?搶到了第21?件商品;
釋放鎖?/locks/test1_lock_0000001405
23?號人?獲取鎖:/locks/test1_lock_0000001406?搶到了第22?件商品;
釋放鎖?/locks/test1_lock_0000001406
12?號人?獲取鎖:/locks/test1_lock_0000001407?搶到了第23?件商品;
釋放鎖?/locks/test1_lock_0000001407
15?號人?獲取鎖:/locks/test1_lock_0000001408?搶到了第24?件商品;
釋放鎖?/locks/test1_lock_0000001408
13?號人?獲取鎖:/locks/test1_lock_0000001409?搶到了第25?件商品;
釋放鎖?/locks/test1_lock_0000001409
34?號人?獲取鎖:/locks/test1_lock_0000001410?搶到了第26?件商品;
釋放鎖?/locks/test1_lock_0000001410
41?號人?獲取鎖:/locks/test1_lock_0000001411?搶到了第27?件商品;
釋放鎖?/locks/test1_lock_0000001411
37?號人?獲取鎖:/locks/test1_lock_0000001412?搶到了第28?件商品;
釋放鎖?/locks/test1_lock_0000001412
1?號人?獲取鎖:/locks/test1_lock_0000001413?搶到了第29?件商品;
釋放鎖?/locks/test1_lock_0000001413
52?號人?獲取鎖:/locks/test1_lock_0000001414?搶到了第30?件商品;
釋放鎖?/locks/test1_lock_0000001414
56?號人?獲取鎖:/locks/test1_lock_0000001415?搶到了第31?件商品;
釋放鎖?/locks/test1_lock_0000001415
26?號人?獲取鎖:/locks/test1_lock_0000001416?搶到了第32?件商品;
釋放鎖?/locks/test1_lock_0000001416
17?號人?獲取鎖:/locks/test1_lock_0000001417?搶到了第33?件商品;
釋放鎖?/locks/test1_lock_0000001417
40?號人?獲取鎖:/locks/test1_lock_0000001418?搶到了第34?件商品;
釋放鎖?/locks/test1_lock_0000001418
4?號人?獲取鎖:/locks/test1_lock_0000001419?搶到了第35?件商品;
釋放鎖?/locks/test1_lock_0000001419
46?號人?獲取鎖:/locks/test1_lock_0000001420?搶到了第36?件商品;
釋放鎖?/locks/test1_lock_0000001420
5?號人?獲取鎖:/locks/test1_lock_0000001421?搶到了第37?件商品;
釋放鎖?/locks/test1_lock_0000001421
54?號人?獲取鎖:/locks/test1_lock_0000001422?搶到了第38?件商品;
釋放鎖?/locks/test1_lock_0000001422
24?號人?獲取鎖:/locks/test1_lock_0000001423?搶到了第39?件商品;
釋放鎖?/locks/test1_lock_0000001423
48?號人?獲取鎖:/locks/test1_lock_0000001424?搶到了第40?件商品;
釋放鎖?/locks/test1_lock_0000001424
50?號人?獲取鎖:/locks/test1_lock_0000001425?搶到了第41?件商品;
釋放鎖?/locks/test1_lock_0000001425
21?號人?獲取鎖:/locks/test1_lock_0000001426?搶到了第42?件商品;
釋放鎖?/locks/test1_lock_0000001426
49?號人?獲取鎖:/locks/test1_lock_0000001427?搶到了第43?件商品;
釋放鎖?/locks/test1_lock_0000001427
36?號人?獲取鎖:/locks/test1_lock_0000001428?搶到了第44?件商品;
釋放鎖?/locks/test1_lock_0000001428
43?號人?獲取鎖:/locks/test1_lock_0000001429?搶到了第45?件商品;
釋放鎖?/locks/test1_lock_0000001429
44?號人?獲取鎖:/locks/test1_lock_0000001430?搶到了第46?件商品;
釋放鎖?/locks/test1_lock_0000001430
30?號人?獲取鎖:/locks/test1_lock_0000001431?搶到了第47?件商品;
釋放鎖?/locks/test1_lock_0000001431
47?號人?獲取鎖:/locks/test1_lock_0000001432?搶到了第48?件商品;
釋放鎖?/locks/test1_lock_0000001432
10?號人?獲取鎖:/locks/test1_lock_0000001433?搶到了第49?件商品;
釋放鎖?/locks/test1_lock_0000001433
9?號人?獲取鎖:/locks/test1_lock_0000001434?搶到了第50?件商品;
釋放鎖?/locks/test1_lock_0000001434
51?號人?獲取鎖:/locks/test1_lock_0000001435?搶到了第51?件商品;
釋放鎖?/locks/test1_lock_0000001435
31?號人?獲取鎖:/locks/test1_lock_0000001436?搶到了第52?件商品;
釋放鎖?/locks/test1_lock_0000001436
16?號人?獲取鎖:/locks/test1_lock_0000001437?搶到了第53?件商品;
釋放鎖?/locks/test1_lock_0000001437
45?號人?獲取鎖:/locks/test1_lock_0000001438?搶到了第54?件商品;
釋放鎖?/locks/test1_lock_0000001438
55?號人?獲取鎖:/locks/test1_lock_0000001439?搶到了第55?件商品;
釋放鎖?/locks/test1_lock_0000001439
53?號人?獲取鎖:/locks/test1_lock_0000001440?搶到了第56?件商品;
釋放鎖?/locks/test1_lock_0000001440
61?號人?獲取鎖:/locks/test1_lock_0000001441?搶到了第57?件商品;
釋放鎖?/locks/test1_lock_0000001441
59?號人?獲取鎖:/locks/test1_lock_0000001442?搶到了第58?件商品;
釋放鎖?/locks/test1_lock_0000001442
58?號人?獲取鎖:/locks/test1_lock_0000001443?搶到了第59?件商品;
釋放鎖?/locks/test1_lock_0000001443
57?號人?獲取鎖:/locks/test1_lock_0000001444?搶到了第60?件商品;
釋放鎖?/locks/test1_lock_0000001444
60?號人?獲取鎖:/locks/test1_lock_0000001445?搶到了第61?件商品;
釋放鎖?/locks/test1_lock_0000001445
92?號人?獲取鎖:/locks/test1_lock_0000001446?搶到了第62?件商品;
釋放鎖?/locks/test1_lock_0000001446
95?號人?獲取鎖:/locks/test1_lock_0000001447?搶到了第63?件商品;
釋放鎖?/locks/test1_lock_0000001447
94?號人?獲取鎖:/locks/test1_lock_0000001448?搶到了第64?件商品;
釋放鎖?/locks/test1_lock_0000001448
96?號人?獲取鎖:/locks/test1_lock_0000001449?搶到了第65?件商品;
釋放鎖?/locks/test1_lock_0000001449
98?號人?獲取鎖:/locks/test1_lock_0000001450?搶到了第66?件商品;
釋放鎖?/locks/test1_lock_0000001450
100?號人?獲取鎖:/locks/test1_lock_0000001451?搶到了第67?件商品;
釋放鎖?/locks/test1_lock_0000001451
101?號人?獲取鎖:/locks/test1_lock_0000001452?搶到了第68?件商品;
釋放鎖?/locks/test1_lock_0000001452
102?號人?獲取鎖:/locks/test1_lock_0000001453?搶到了第69?件商品;
釋放鎖?/locks/test1_lock_0000001453
104?號人?獲取鎖:/locks/test1_lock_0000001454?搶到了第70?件商品;
釋放鎖?/locks/test1_lock_0000001454
117?號人?獲取鎖:/locks/test1_lock_0000001455?搶到了第71?件商品;
釋放鎖?/locks/test1_lock_0000001455
116?號人?獲取鎖:/locks/test1_lock_0000001456?搶到了第72?件商品;
釋放鎖?/locks/test1_lock_0000001456
113?號人?獲取鎖:/locks/test1_lock_0000001457?搶到了第73?件商品;
釋放鎖?/locks/test1_lock_0000001457
119?號人?獲取鎖:/locks/test1_lock_0000001458?搶到了第74?件商品;
釋放鎖?/locks/test1_lock_0000001458
120?號人?獲取鎖:/locks/test1_lock_0000001459?搶到了第75?件商品;
釋放鎖?/locks/test1_lock_0000001459
111?號人?獲取鎖:/locks/test1_lock_0000001460?搶到了第76?件商品;
釋放鎖?/locks/test1_lock_0000001460
115?號人?獲取鎖:/locks/test1_lock_0000001461?搶到了第77?件商品;
釋放鎖?/locks/test1_lock_0000001461
107?號人?獲取鎖:/locks/test1_lock_0000001462?搶到了第78?件商品;
釋放鎖?/locks/test1_lock_0000001462
114?號人?獲取鎖:/locks/test1_lock_0000001463?搶到了第79?件商品;
釋放鎖?/locks/test1_lock_0000001463
109?號人?獲取鎖:/locks/test1_lock_0000001464?搶到了第80?件商品;
釋放鎖?/locks/test1_lock_0000001464
63?號人?獲取鎖:/locks/test1_lock_0000001465?搶到了第81?件商品;
釋放鎖?/locks/test1_lock_0000001465
62?號人?獲取鎖:/locks/test1_lock_0000001466?搶到了第82?件商品;
釋放鎖?/locks/test1_lock_0000001466
88?號人?獲取鎖:/locks/test1_lock_0000001467?搶到了第83?件商品;
釋放鎖?/locks/test1_lock_0000001467
81?號人?獲取鎖:/locks/test1_lock_0000001468?搶到了第84?件商品;
釋放鎖?/locks/test1_lock_0000001468
82?號人?獲取鎖:/locks/test1_lock_0000001469?搶到了第85?件商品;
釋放鎖?/locks/test1_lock_0000001469
87?號人?獲取鎖:/locks/test1_lock_0000001470?搶到了第86?件商品;
釋放鎖?/locks/test1_lock_0000001470
64?號人?獲取鎖:/locks/test1_lock_0000001471?搶到了第87?件商品;
釋放鎖?/locks/test1_lock_0000001471
84?號人?獲取鎖:/locks/test1_lock_0000001472?搶到了第88?件商品;
釋放鎖?/locks/test1_lock_0000001472
68?號人?獲取鎖:/locks/test1_lock_0000001473?搶到了第89?件商品;
釋放鎖?/locks/test1_lock_0000001473
67?號人?獲取鎖:/locks/test1_lock_0000001474?搶到了第90?件商品;
釋放鎖?/locks/test1_lock_0000001474
99?號人?獲取鎖:/locks/test1_lock_0000001475?搶到了第91?件商品;
釋放鎖?/locks/test1_lock_0000001475
78?號人?獲取鎖:/locks/test1_lock_0000001476?搶到了第92?件商品;
釋放鎖?/locks/test1_lock_0000001476
73?號人?獲取鎖:/locks/test1_lock_0000001477?搶到了第93?件商品;
釋放鎖?/locks/test1_lock_0000001477
71?號人?獲取鎖:/locks/test1_lock_0000001478?搶到了第94?件商品;
釋放鎖?/locks/test1_lock_0000001478
83?號人?獲取鎖:/locks/test1_lock_0000001479?搶到了第95?件商品;
釋放鎖?/locks/test1_lock_0000001479
91?號人?獲取鎖:/locks/test1_lock_0000001480?搶到了第96?件商品;
釋放鎖?/locks/test1_lock_0000001480
90?號人?獲取鎖:/locks/test1_lock_0000001481?搶到了第97?件商品;
釋放鎖?/locks/test1_lock_0000001481
65?號人?獲取鎖:/locks/test1_lock_0000001482?搶到了第98?件商品;
釋放鎖?/locks/test1_lock_0000001482
77?號人?獲取鎖:/locks/test1_lock_0000001483?搶到了第99?件商品;
釋放鎖?/locks/test1_lock_0000001483
76?號人?獲取鎖:/locks/test1_lock_0000001484?搶到了第100?件商品;
釋放鎖?/locks/test1_lock_0000001484
釋放鎖?/locks/test1_lock_0000001485
75?號人?太悲劇了,沒搶到商品...
釋放鎖?/locks/test1_lock_0000001486
69?號人?太悲劇了,沒搶到商品...
釋放鎖?/locks/test1_lock_0000001487
89?號人?太悲劇了,沒搶到商品...
釋放鎖?/locks/test1_lock_0000001488
105?號人?太悲劇了,沒搶到商品...
釋放鎖?/locks/test1_lock_0000001489
85?號人?太悲劇了,沒搶到商品...
釋放鎖?/locks/test1_lock_0000001490
74?號人?太悲劇了,沒搶到商品...
釋放鎖?/locks/test1_lock_0000001491
66?號人?太悲劇了,沒搶到商品...
釋放鎖?/locks/test1_lock_0000001492
112?號人?太悲劇了,沒搶到商品...
釋放鎖?/locks/test1_lock_0000001493
釋放鎖?/locks/test1_lock_0000001494
釋放鎖?/locks/test1_lock_0000001495
70?號人?太悲劇了,沒搶到商品...
108?號人?太悲劇了,沒搶到商品...
79?號人?太悲劇了,沒搶到商品...
釋放鎖?/locks/test1_lock_0000001496
釋放鎖?/locks/test1_lock_0000001497
93?號人?太悲劇了,沒搶到商品...
釋放鎖?/locks/test1_lock_0000001498
106?號人?太悲劇了,沒搶到商品...
釋放鎖?/locks/test1_lock_0000001499
103?號人?太悲劇了,沒搶到商品...
釋放鎖?/locks/test1_lock_0000001500
釋放鎖?/locks/test1_lock_0000001501
72?號人?太悲劇了,沒搶到商品...
80?號人?太悲劇了,沒搶到商品...
118?號人?太悲劇了,沒搶到商品...
釋放鎖?/locks/test1_lock_0000001502
86?號人?太悲劇了,沒搶到商品...
釋放鎖?/locks/test1_lock_0000001503
97?號人?太悲劇了,沒搶到商品...
釋放鎖?/locks/test1_lock_0000001504
110?號人?太悲劇了,沒搶到商品...
入口類:
package?com.demo.index;
import?com.demo.utils.DistributedLock;
import?com.jfinal.core.Controller;
import?com.jfinal.plugin.activerecord.Db;
import?com.jfinal.plugin.activerecord.Record;
/**
?*?秒殺/zookeeper?分布式鎖
?*?
?*?@author?sun
?*/
public?class?SecKillForZookeeperController?extends?Controller?{
????public?static?int?goodsTotalNum?=?100;
????public?void?index()?{
????????//每一次新的請求都會模擬搶購100件商品,所以先恢復商品的數量,這個可以不要,也可以手動去更新數據庫
????????Db.update("update?t_goods?set?num?=???where?id?=?1",?goodsTotalNum);
????????Record?goods?=?Db.findFirst("select?*?from?t_goods?where?id?=?1");
????????Integer?num?=?0;
????????if(goods!=null){
????????????num?=?goods.getInt("num");
????????}
????????SecKillZookeeper?sk?=?new?SecKillZookeeper(num);
????????//?模擬120個人搶購。?模擬120人分別在不同的服務器進行發起請求
????????for?(int?i?=?1;?i?<=?120;?i++)?{
????????????new?Thread(sk,?i?+?"?號人").start();
????????}
????????renderHtml("<center><h2>搶購成功!</h2></center>");
????}
}
/**
?*?這里我們只是簡單演示實現方式,至于事務等其他的都不添加了。
?*?
?*?@author?sun
?*/
class?SecKillZookeeper?implements?Runnable?{
????private?int?num?=?0;
????public?SecKillZookeeper(int?num)?{
????????this.num?=?num;
????}
????@Override
????public?void?run()?{
????????DistributedLock?lock?=?null;
????????try?{
????????????lock?=?new?DistributedLock("127.0.0.1:2181",?"test1");
????????????lock.lock();
????????????if?(num?>?0)?{
????????????????sale(lock);
????????????????return?;
????????????}
????????}?finally?{
????????????if?(lock?!=?null)?{
????????????????lock.unlock();
????????????}
????????}
????????System.err.println(Thread.currentThread().getName()?+?"?太悲劇了,沒搶到商品...");
????}
????private?void?sale(DistributedLock?lock)?{
????????if(num>0){
????????????Db.update("update?t_goods?set?num=num-1?where?id?=?1");
????????????num--;
????????????System.out.println(Thread.currentThread().getName()+"?獲取鎖:"+lock.CURRENT_LOCK+"?搶到了第"+(SecKillForZookeeperController.goodsTotalNum?-?num)+"?件商品;");
????????}
????}
}
打印結果:?
39?號人?獲取鎖:/locks/test1_lock_0000001385?搶到了第1?件商品;
釋放鎖?/locks/test1_lock_0000001385
35?號人?獲取鎖:/locks/test1_lock_0000001386?搶到了第2?件商品;
釋放鎖?/locks/test1_lock_0000001386
25?號人?獲取鎖:/locks/test1_lock_0000001387?搶到了第3?件商品;
釋放鎖?/locks/test1_lock_0000001387
42?號人?獲取鎖:/locks/test1_lock_0000001388?搶到了第4?件商品;
釋放鎖?/locks/test1_lock_0000001388
19?號人?獲取鎖:/locks/test1_lock_0000001389?搶到了第5?件商品;
釋放鎖?/locks/test1_lock_0000001389
38?號人?獲取鎖:/locks/test1_lock_0000001390?搶到了第6?件商品;
釋放鎖?/locks/test1_lock_0000001390
22?號人?獲取鎖:/locks/test1_lock_0000001391?搶到了第7?件商品;
釋放鎖?/locks/test1_lock_0000001391
18?號人?獲取鎖:/locks/test1_lock_0000001392?搶到了第8?件商品;
釋放鎖?/locks/test1_lock_0000001392
27?號人?獲取鎖:/locks/test1_lock_0000001393?搶到了第9?件商品;
釋放鎖?/locks/test1_lock_0000001393
28?號人?獲取鎖:/locks/test1_lock_0000001394?搶到了第10?件商品;
釋放鎖?/locks/test1_lock_0000001394
2?號人?獲取鎖:/locks/test1_lock_0000001395?搶到了第11?件商品;
釋放鎖?/locks/test1_lock_0000001395
14?號人?獲取鎖:/locks/test1_lock_0000001396?搶到了第12?件商品;
釋放鎖?/locks/test1_lock_0000001396
20?號人?獲取鎖:/locks/test1_lock_0000001397?搶到了第13?件商品;
釋放鎖?/locks/test1_lock_0000001397
11?號人?獲取鎖:/locks/test1_lock_0000001398?搶到了第14?件商品;
釋放鎖?/locks/test1_lock_0000001398
6?號人?獲取鎖:/locks/test1_lock_0000001399?搶到了第15?件商品;
釋放鎖?/locks/test1_lock_0000001399
7?號人?獲取鎖:/locks/test1_lock_0000001400?搶到了第16?件商品;
釋放鎖?/locks/test1_lock_0000001400
29?號人?獲取鎖:/locks/test1_lock_0000001401?搶到了第17?件商品;
釋放鎖?/locks/test1_lock_0000001401
3?號人?獲取鎖:/locks/test1_lock_0000001402?搶到了第18?件商品;
釋放鎖?/locks/test1_lock_0000001402
8?號人?獲取鎖:/locks/test1_lock_0000001403?搶到了第19?件商品;
釋放鎖?/locks/test1_lock_0000001403
32?號人?獲取鎖:/locks/test1_lock_0000001404?搶到了第20?件商品;
釋放鎖?/locks/test1_lock_0000001404
33?號人?獲取鎖:/locks/test1_lock_0000001405?搶到了第21?件商品;
釋放鎖?/locks/test1_lock_0000001405
23?號人?獲取鎖:/locks/test1_lock_0000001406?搶到了第22?件商品;
釋放鎖?/locks/test1_lock_0000001406
12?號人?獲取鎖:/locks/test1_lock_0000001407?搶到了第23?件商品;
釋放鎖?/locks/test1_lock_0000001407
15?號人?獲取鎖:/locks/test1_lock_0000001408?搶到了第24?件商品;
釋放鎖?/locks/test1_lock_0000001408
13?號人?獲取鎖:/locks/test1_lock_0000001409?搶到了第25?件商品;
釋放鎖?/locks/test1_lock_0000001409
34?號人?獲取鎖:/locks/test1_lock_0000001410?搶到了第26?件商品;
釋放鎖?/locks/test1_lock_0000001410
41?號人?獲取鎖:/locks/test1_lock_0000001411?搶到了第27?件商品;
釋放鎖?/locks/test1_lock_0000001411
37?號人?獲取鎖:/locks/test1_lock_0000001412?搶到了第28?件商品;
釋放鎖?/locks/test1_lock_0000001412
1?號人?獲取鎖:/locks/test1_lock_0000001413?搶到了第29?件商品;
釋放鎖?/locks/test1_lock_0000001413
52?號人?獲取鎖:/locks/test1_lock_0000001414?搶到了第30?件商品;
釋放鎖?/locks/test1_lock_0000001414
56?號人?獲取鎖:/locks/test1_lock_0000001415?搶到了第31?件商品;
釋放鎖?/locks/test1_lock_0000001415
26?號人?獲取鎖:/locks/test1_lock_0000001416?搶到了第32?件商品;
釋放鎖?/locks/test1_lock_0000001416
17?號人?獲取鎖:/locks/test1_lock_0000001417?搶到了第33?件商品;
釋放鎖?/locks/test1_lock_0000001417
40?號人?獲取鎖:/locks/test1_lock_0000001418?搶到了第34?件商品;
釋放鎖?/locks/test1_lock_0000001418
4?號人?獲取鎖:/locks/test1_lock_0000001419?搶到了第35?件商品;
釋放鎖?/locks/test1_lock_0000001419
46?號人?獲取鎖:/locks/test1_lock_0000001420?搶到了第36?件商品;
釋放鎖?/locks/test1_lock_0000001420
5?號人?獲取鎖:/locks/test1_lock_0000001421?搶到了第37?件商品;
釋放鎖?/locks/test1_lock_0000001421
54?號人?獲取鎖:/locks/test1_lock_0000001422?搶到了第38?件商品;
釋放鎖?/locks/test1_lock_0000001422
24?號人?獲取鎖:/locks/test1_lock_0000001423?搶到了第39?件商品;
釋放鎖?/locks/test1_lock_0000001423
48?號人?獲取鎖:/locks/test1_lock_0000001424?搶到了第40?件商品;
釋放鎖?/locks/test1_lock_0000001424
50?號人?獲取鎖:/locks/test1_lock_0000001425?搶到了第41?件商品;
釋放鎖?/locks/test1_lock_0000001425
21?號人?獲取鎖:/locks/test1_lock_0000001426?搶到了第42?件商品;
釋放鎖?/locks/test1_lock_0000001426
49?號人?獲取鎖:/locks/test1_lock_0000001427?搶到了第43?件商品;
釋放鎖?/locks/test1_lock_0000001427
36?號人?獲取鎖:/locks/test1_lock_0000001428?搶到了第44?件商品;
釋放鎖?/locks/test1_lock_0000001428
43?號人?獲取鎖:/locks/test1_lock_0000001429?搶到了第45?件商品;
釋放鎖?/locks/test1_lock_0000001429
44?號人?獲取鎖:/locks/test1_lock_0000001430?搶到了第46?件商品;
釋放鎖?/locks/test1_lock_0000001430
30?號人?獲取鎖:/locks/test1_lock_0000001431?搶到了第47?件商品;
釋放鎖?/locks/test1_lock_0000001431
47?號人?獲取鎖:/locks/test1_lock_0000001432?搶到了第48?件商品;
釋放鎖?/locks/test1_lock_0000001432
10?號人?獲取鎖:/locks/test1_lock_0000001433?搶到了第49?件商品;
釋放鎖?/locks/test1_lock_0000001433
9?號人?獲取鎖:/locks/test1_lock_0000001434?搶到了第50?件商品;
釋放鎖?/locks/test1_lock_0000001434
51?號人?獲取鎖:/locks/test1_lock_0000001435?搶到了第51?件商品;
釋放鎖?/locks/test1_lock_0000001435
31?號人?獲取鎖:/locks/test1_lock_0000001436?搶到了第52?件商品;
釋放鎖?/locks/test1_lock_0000001436
16?號人?獲取鎖:/locks/test1_lock_0000001437?搶到了第53?件商品;
釋放鎖?/locks/test1_lock_0000001437
45?號人?獲取鎖:/locks/test1_lock_0000001438?搶到了第54?件商品;
釋放鎖?/locks/test1_lock_0000001438
55?號人?獲取鎖:/locks/test1_lock_0000001439?搶到了第55?件商品;
釋放鎖?/locks/test1_lock_0000001439
53?號人?獲取鎖:/locks/test1_lock_0000001440?搶到了第56?件商品;
釋放鎖?/locks/test1_lock_0000001440
61?號人?獲取鎖:/locks/test1_lock_0000001441?搶到了第57?件商品;
釋放鎖?/locks/test1_lock_0000001441
59?號人?獲取鎖:/locks/test1_lock_0000001442?搶到了第58?件商品;
釋放鎖?/locks/test1_lock_0000001442
58?號人?獲取鎖:/locks/test1_lock_0000001443?搶到了第59?件商品;
釋放鎖?/locks/test1_lock_0000001443
57?號人?獲取鎖:/locks/test1_lock_0000001444?搶到了第60?件商品;
釋放鎖?/locks/test1_lock_0000001444
60?號人?獲取鎖:/locks/test1_lock_0000001445?搶到了第61?件商品;
釋放鎖?/locks/test1_lock_0000001445
92?號人?獲取鎖:/locks/test1_lock_0000001446?搶到了第62?件商品;
釋放鎖?/locks/test1_lock_0000001446
95?號人?獲取鎖:/locks/test1_lock_0000001447?搶到了第63?件商品;
釋放鎖?/locks/test1_lock_0000001447
94?號人?獲取鎖:/locks/test1_lock_0000001448?搶到了第64?件商品;
釋放鎖?/locks/test1_lock_0000001448
96?號人?獲取鎖:/locks/test1_lock_0000001449?搶到了第65?件商品;
釋放鎖?/locks/test1_lock_0000001449
98?號人?獲取鎖:/locks/test1_lock_0000001450?搶到了第66?件商品;
釋放鎖?/locks/test1_lock_0000001450
100?號人?獲取鎖:/locks/test1_lock_0000001451?搶到了第67?件商品;
釋放鎖?/locks/test1_lock_0000001451
101?號人?獲取鎖:/locks/test1_lock_0000001452?搶到了第68?件商品;
釋放鎖?/locks/test1_lock_0000001452
102?號人?獲取鎖:/locks/test1_lock_0000001453?搶到了第69?件商品;
釋放鎖?/locks/test1_lock_0000001453
104?號人?獲取鎖:/locks/test1_lock_0000001454?搶到了第70?件商品;
釋放鎖?/locks/test1_lock_0000001454
117?號人?獲取鎖:/locks/test1_lock_0000001455?搶到了第71?件商品;
釋放鎖?/locks/test1_lock_0000001455
116?號人?獲取鎖:/locks/test1_lock_0000001456?搶到了第72?件商品;
釋放鎖?/locks/test1_lock_0000001456
113?號人?獲取鎖:/locks/test1_lock_0000001457?搶到了第73?件商品;
釋放鎖?/locks/test1_lock_0000001457
119?號人?獲取鎖:/locks/test1_lock_0000001458?搶到了第74?件商品;
釋放鎖?/locks/test1_lock_0000001458
120?號人?獲取鎖:/locks/test1_lock_0000001459?搶到了第75?件商品;
釋放鎖?/locks/test1_lock_0000001459
111?號人?獲取鎖:/locks/test1_lock_0000001460?搶到了第76?件商品;
釋放鎖?/locks/test1_lock_0000001460
115?號人?獲取鎖:/locks/test1_lock_0000001461?搶到了第77?件商品;
釋放鎖?/locks/test1_lock_0000001461
107?號人?獲取鎖:/locks/test1_lock_0000001462?搶到了第78?件商品;
釋放鎖?/locks/test1_lock_0000001462
114?號人?獲取鎖:/locks/test1_lock_0000001463?搶到了第79?件商品;
釋放鎖?/locks/test1_lock_0000001463
109?號人?獲取鎖:/locks/test1_lock_0000001464?搶到了第80?件商品;
釋放鎖?/locks/test1_lock_0000001464
63?號人?獲取鎖:/locks/test1_lock_0000001465?搶到了第81?件商品;
釋放鎖?/locks/test1_lock_0000001465
62?號人?獲取鎖:/locks/test1_lock_0000001466?搶到了第82?件商品;
釋放鎖?/locks/test1_lock_0000001466
88?號人?獲取鎖:/locks/test1_lock_0000001467?搶到了第83?件商品;
釋放鎖?/locks/test1_lock_0000001467
81?號人?獲取鎖:/locks/test1_lock_0000001468?搶到了第84?件商品;
釋放鎖?/locks/test1_lock_0000001468
82?號人?獲取鎖:/locks/test1_lock_0000001469?搶到了第85?件商品;
釋放鎖?/locks/test1_lock_0000001469
87?號人?獲取鎖:/locks/test1_lock_0000001470?搶到了第86?件商品;
釋放鎖?/locks/test1_lock_0000001470
64?號人?獲取鎖:/locks/test1_lock_0000001471?搶到了第87?件商品;
釋放鎖?/locks/test1_lock_0000001471
84?號人?獲取鎖:/locks/test1_lock_0000001472?搶到了第88?件商品;
釋放鎖?/locks/test1_lock_0000001472
68?號人?獲取鎖:/locks/test1_lock_0000001473?搶到了第89?件商品;
釋放鎖?/locks/test1_lock_0000001473
67?號人?獲取鎖:/locks/test1_lock_0000001474?搶到了第90?件商品;
釋放鎖?/locks/test1_lock_0000001474
99?號人?獲取鎖:/locks/test1_lock_0000001475?搶到了第91?件商品;
釋放鎖?/locks/test1_lock_0000001475
78?號人?獲取鎖:/locks/test1_lock_0000001476?搶到了第92?件商品;
釋放鎖?/locks/test1_lock_0000001476
73?號人?獲取鎖:/locks/test1_lock_0000001477?搶到了第93?件商品;
釋放鎖?/locks/test1_lock_0000001477
71?號人?獲取鎖:/locks/test1_lock_0000001478?搶到了第94?件商品;
釋放鎖?/locks/test1_lock_0000001478
83?號人?獲取鎖:/locks/test1_lock_0000001479?搶到了第95?件商品;
釋放鎖?/locks/test1_lock_0000001479
91?號人?獲取鎖:/locks/test1_lock_0000001480?搶到了第96?件商品;
釋放鎖?/locks/test1_lock_0000001480
90?號人?獲取鎖:/locks/test1_lock_0000001481?搶到了第97?件商品;
釋放鎖?/locks/test1_lock_0000001481
65?號人?獲取鎖:/locks/test1_lock_0000001482?搶到了第98?件商品;
釋放鎖?/locks/test1_lock_0000001482
77?號人?獲取鎖:/locks/test1_lock_0000001483?搶到了第99?件商品;
釋放鎖?/locks/test1_lock_0000001483
76?號人?獲取鎖:/locks/test1_lock_0000001484?搶到了第100?件商品;
釋放鎖?/locks/test1_lock_0000001484
釋放鎖?/locks/test1_lock_0000001485
75?號人?太悲劇了,沒搶到商品...
釋放鎖?/locks/test1_lock_0000001486
69?號人?太悲劇了,沒搶到商品...
釋放鎖?/locks/test1_lock_0000001487
89?號人?太悲劇了,沒搶到商品...
釋放鎖?/locks/test1_lock_0000001488
105?號人?太悲劇了,沒搶到商品...
釋放鎖?/locks/test1_lock_0000001489
85?號人?太悲劇了,沒搶到商品...
釋放鎖?/locks/test1_lock_0000001490
74?號人?太悲劇了,沒搶到商品...
釋放鎖?/locks/test1_lock_0000001491
66?號人?太悲劇了,沒搶到商品...
釋放鎖?/locks/test1_lock_0000001492
112?號人?太悲劇了,沒搶到商品...
釋放鎖?/locks/test1_lock_0000001493
釋放鎖?/locks/test1_lock_0000001494
釋放鎖?/locks/test1_lock_0000001495
70?號人?太悲劇了,沒搶到商品...
108?號人?太悲劇了,沒搶到商品...
79?號人?太悲劇了,沒搶到商品...
釋放鎖?/locks/test1_lock_0000001496
釋放鎖?/locks/test1_lock_0000001497
93?號人?太悲劇了,沒搶到商品...
釋放鎖?/locks/test1_lock_0000001498
106?號人?太悲劇了,沒搶到商品...
釋放鎖?/locks/test1_lock_0000001499
103?號人?太悲劇了,沒搶到商品...
釋放鎖?/locks/test1_lock_0000001500
釋放鎖?/locks/test1_lock_0000001501
72?號人?太悲劇了,沒搶到商品...
80?號人?太悲劇了,沒搶到商品...
118?號人?太悲劇了,沒搶到商品...
釋放鎖?/locks/test1_lock_0000001502
86?號人?太悲劇了,沒搶到商品...
釋放鎖?/locks/test1_lock_0000001503
97?號人?太悲劇了,沒搶到商品...
釋放鎖?/locks/test1_lock_0000001504
110?號人?太悲劇了,沒搶到商品...
總體來說,如果了解到整個實現流程,使用zookeeper實現分布式鎖并不是很困難,不過這也只是一個簡單的實現,與前面實現Redis實現相比,本實現的穩定性更強,這是因為zookeeper的特性所致,在外界看來,zookeeper集群中每一個節點都是一致的。
在此我向大家推薦一個架構學習交流群。交流學習群號:897889510 加群獲得以上學習視頻,群里面還會分享一些資深架構師錄制的視頻錄像:有Spring,MyBatis,Netty源碼分析,高并發、高性能、分布式、微服務架構的原理,JVM性能優化、分布式架構等這些成為架構師必備的知識體系。還能領取免費的學習資源,目前受益良多
t_goods表結構:
CREATE?TABLE?`d_sunjs_test`.`t_goods`??(
??`id`?int(11)?NOT?NULL?AUTO_INCREMENT,
??`name`?varchar(255)?CHARACTER?SET?utf8?COLLATE?utf8_general_ci?NULL?DEFAULT?NULL,
??`num`?int(11)?NULL?DEFAULT?NULL,
??`version`?int(11)?NULL?DEFAULT?1?COMMENT?'樂觀鎖',
??PRIMARY?KEY?(`id`)?USING?BTREE
)?ENGINE?=?InnoDB?AUTO_INCREMENT?=?2?CHARACTER?SET?=?utf8?COLLATE?=?utf8_general_ci?ROW_FORMAT?=?Dynamic;
測試的時候記得啟動zookeeper服務!