背景

继续上一篇文章:http://agapple.iteye.com/blog/1183972 ,项目中需要对分布式任务进行调度,那对应的分布式lock实现在所难免。

这一周,在基于BooleanMutex的基础上,实现了zookeeper的分布式锁,用于控制多进程+多线程的lock控制

算法

可以预先看一下zookeeper的官方文档:

lock操作过程:
  • 首先为一个lock场景,在zookeeper中指定对应的一个根节点,用于记录资源竞争的内容
  • 每个lock创建后,会lazy在zookeeper中创建一个node节点,表明对应的资源竞争标识。 (小技巧:node节点为EPHEMERAL_SEQUENTIAL,自增长的临时节点)
  • 进行lock操作时,获取对应lock根节点下的所有字节点,也即处于竞争中的资源标识
  • 按照Fair竞争的原则,按照对应的自增内容做排序,取出编号最小的一个节点做为lock的owner,判断自己的节点id是否就为owner id,如果是则返回,lock成功。
  • 如果自己非owner id,按照排序的结果找到序号比自己前一位的id,关注它锁释放的操作(也就是exist watcher),形成一个链式的触发过程。
unlock操作过程:
  • 将自己id对应的节点删除即可,对应的下一个排队的节点就可以收到Watcher事件,从而被唤醒得到锁后退出
 
其中的几个关键点:
  1. node节点选择为EPHEMERAL_SEQUENTIAL很重要。 * 自增长的特性,可以方便构建一个基于Fair特性的锁,前一个节点唤醒后一个节点,形成一个链式的触发过程。可以有效的避免"惊群效应"(一个锁释放,所有等待的线程都被唤醒),有针对性的唤醒,提升性能。 * 选择一个EPHEMERAL临时节点的特性。因为和zookeeper交互是一个网络操作,不可控因素过多,比如网络断了,上一个节点释放锁的操作会失败。临时节点是和对应的session挂接的,session一旦超时或者异常退出其节点就会消失,类似于ReentrantLock中等待队列Thread的被中断处理。
  2. 获取lock操作是一个阻塞的操作,而对应的Watcher是一个异步事件,所以需要使用信号进行通知,正好使用上一篇文章中提到的BooleanMutex,可以比较方便的解决锁重入的问题。(锁重入可以理解为多次读操作,锁释放为写抢占操作)
 
注意:
  • 使用EPHEMERAL会引出一个风险:在非正常情况下,网络延迟比较大会出现session timeout,zookeeper就会认为该client已关闭,从而销毁其id标示,竞争资源的下一个id就可以获取锁。这时可能会有两个process同时拿到锁在跑任务,所以设置好session timeout很重要。
  • 同样使用PERSISTENT同样会存在一个死锁的风险,进程异常退出后,对应的竞争资源id一直没有删除,下一个id一直无法获取到锁对象。
没有两全其美的做法,两者取其一,选择自己一个能接受的即可

代码

  1. public class DistributedLock {
  2. private static final byte[]  data      = { 0x12, 0x34 };
  3. private ZooKeeperx           zookeeper = ZooKeeperClient.getInstance();
  4. private final String         root;                                     //根节点路径
  5. private String               id;
  6. private LockNode             idName;
  7. private String               ownerId;
  8. private String               lastChildId;
  9. private Throwable            other     = null;
  10. private KeeperException      exception = null;
  11. private InterruptedException interrupt = null;
  12. public DistributedLock(String root) {
  13. this.root = root;
  14. ensureExists(root);
  15. }
  16. /**
  17. * 尝试获取锁操作,阻塞式可被中断
  18. */
  19. public void lock() throws InterruptedException, KeeperException {
  20. // 可能初始化的时候就失败了
  21. if (exception != null) {
  22. throw exception;
  23. }
  24. if (interrupt != null) {
  25. throw interrupt;
  26. }
  27. if (other != null) {
  28. throw new NestableRuntimeException(other);
  29. }
  30. if (isOwner()) {//锁重入
  31. return;
  32. }
  33. BooleanMutex mutex = new BooleanMutex();
  34. acquireLock(mutex);
  35. // 避免zookeeper重启后导致watcher丢失,会出现死锁使用了超时进行重试
  36. try {
  37. mutex.get(DEFAULT_TIMEOUT_PERIOD, TimeUnit.MICROSECONDS);// 阻塞等待值为true
  38. // mutex.get();
  39. } catch (TimeoutException e) {
  40. if (!mutex.state()) {
  41. lock();
  42. }
  43. }
  44. if (exception != null) {
  45. throw exception;
  46. }
  47. if (interrupt != null) {
  48. throw interrupt;
  49. }
  50. if (other != null) {
  51. throw new NestableRuntimeException(other);
  52. }
  53. }
  54. /**
  55. * 尝试获取锁对象, 不会阻塞
  56. *
  57. * @throws InterruptedException
  58. * @throws KeeperException
  59. */
  60. public boolean tryLock() throws KeeperException {
  61. // 可能初始化的时候就失败了
  62. if (exception != null) {
  63. throw exception;
  64. }
  65. if (isOwner()) {//锁重入
  66. return true;
  67. }
  68. acquireLock(null);
  69. if (exception != null) {
  70. throw exception;
  71. }
  72. if (interrupt != null) {
  73. Thread.currentThread().interrupt();
  74. }
  75. if (other != null) {
  76. throw new NestableRuntimeException(other);
  77. }
  78. return isOwner();
  79. }
  80. /**
  81. * 释放锁对象
  82. */
  83. public void unlock() throws KeeperException {
  84. if (id != null) {
  85. try {
  86. zookeeper.delete(root + "/" + id, -1);
  87. } catch (InterruptedException e) {
  88. Thread.currentThread().interrupt();
  89. } catch (KeeperException.NoNodeException e) {
  90. // do nothing
  91. } finally {
  92. id = null;
  93. }
  94. } else {
  95. //do nothing
  96. }
  97. }
  98. private void ensureExists(final String path) {
  99. try {
  100. Stat stat = zookeeper.exists(path, false);
  101. if (stat != null) {
  102. return;
  103. }
  104. zookeeper.create(path, data, CreateMode.PERSISTENT);
  105. } catch (KeeperException e) {
  106. exception = e;
  107. } catch (InterruptedException e) {
  108. Thread.currentThread().interrupt();
  109. interrupt = e;
  110. }
  111. }
  112. /**
  113. * 返回锁对象对应的path
  114. */
  115. public String getRoot() {
  116. return root;
  117. }
  118. /**
  119. * 判断当前是不是锁的owner
  120. */
  121. public boolean isOwner() {
  122. return id != null && ownerId != null && id.equals(ownerId);
  123. }
  124. /**
  125. * 返回当前的节点id
  126. */
  127. public String getId() {
  128. return this.id;
  129. }
  130. // ===================== helper method =============================
  131. /**
  132. * 执行lock操作,允许传递watch变量控制是否需要阻塞lock操作
  133. */
  134. private Boolean acquireLock(final BooleanMutex mutex) {
  135. try {
  136. do {
  137. if (id == null) {//构建当前lock的唯一标识
  138. long sessionId = zookeeper.getDelegate().getSessionId();
  139. String prefix = "x-" + sessionId + "-";
  140. //如果第一次,则创建一个节点
  141. String path = zookeeper.create(root + "/" + prefix, data,
  142. CreateMode.EPHEMERAL_SEQUENTIAL);
  143. int index = path.lastIndexOf("/");
  144. id = StringUtils.substring(path, index + 1);
  145. idName = new LockNode(id);
  146. }
  147. if (id != null) {
  148. List<String> names = zookeeper.getChildren(root, false);
  149. if (names.isEmpty()) {
  150. id = null;//异常情况,重新创建一个
  151. } else {
  152. //对节点进行排序
  153. SortedSet<LockNode> sortedNames = new TreeSet<LockNode>();
  154. for (String name : names) {
  155. sortedNames.add(new LockNode(name));
  156. }
  157. if (sortedNames.contains(idName) == false) {
  158. id = null;//清空为null,重新创建一个
  159. continue;
  160. }
  161. //将第一个节点做为ownerId
  162. ownerId = sortedNames.first().getName();
  163. if (mutex != null && isOwner()) {
  164. mutex.set(true);//直接更新状态,返回
  165. return true;
  166. } else if (mutex == null) {
  167. return isOwner();
  168. }
  169. SortedSet<LockNode> lessThanMe = sortedNames.headSet(idName);
  170. if (!lessThanMe.isEmpty()) {
  171. //关注一下排队在自己之前的最近的一个节点
  172. LockNode lastChildName = lessThanMe.last();
  173. lastChildId = lastChildName.getName();
  174. //异步watcher处理
  175. zookeeper.exists(root + "/" + lastChildId, new AsyncWatcher() {
  176. public void asyncProcess(WatchedEvent event) {
  177. acquireLock(mutex);
  178. }
  179. });
  180. if (stat == null) {
  181. acquireLock(mutex);// 如果节点不存在,需要自己重新触发一下,watcher不会被挂上去
  182. }
  183. } else {
  184. if (isOwner()) {
  185. mutex.set(true);
  186. } else {
  187. id = null;// 可能自己的节点已超时挂了,所以id和ownerId不相同
  188. }
  189. }
  190. }
  191. }
  192. } while (id == null);
  193. } catch (KeeperException e) {
  194. exception = e;
  195. if (mutex != null) {
  196. mutex.set(true);
  197. }
  198. } catch (InterruptedException e) {
  199. interrupt = e;
  200. if (mutex != null) {
  201. mutex.set(true);
  202. }
  203. } catch (Throwable e) {
  204. other = e;
  205. if (mutex != null) {
  206. mutex.set(true);
  207. }
  208. }
  209. if (isOwner() && mutex != null) {
  210. mutex.set(true);
  211. }
  212. return Boolean.FALSE;
  213. }
  214. }
public class DistributedLock {

    private static final byte[]  data      = { 0x12, 0x34 };
private ZooKeeperx zookeeper = ZooKeeperClient.getInstance();
private final String root; //根节点路径
private String id;
private LockNode idName;
private String ownerId;
private String lastChildId;
private Throwable other = null;
private KeeperException exception = null;
private InterruptedException interrupt = null; public DistributedLock(String root) {
this.root = root;
ensureExists(root);
} /**
* 尝试获取锁操作,阻塞式可被中断
*/
public void lock() throws InterruptedException, KeeperException {
// 可能初始化的时候就失败了
if (exception != null) {
throw exception;
} if (interrupt != null) {
throw interrupt;
} if (other != null) {
throw new NestableRuntimeException(other);
} if (isOwner()) {//锁重入
return;
} BooleanMutex mutex = new BooleanMutex();
acquireLock(mutex);
// 避免zookeeper重启后导致watcher丢失,会出现死锁使用了超时进行重试
try {
mutex.get(DEFAULT_TIMEOUT_PERIOD, TimeUnit.MICROSECONDS);// 阻塞等待值为true
// mutex.get();
} catch (TimeoutException e) {
if (!mutex.state()) {
lock();
}
} if (exception != null) {
throw exception;
} if (interrupt != null) {
throw interrupt;
} if (other != null) {
throw new NestableRuntimeException(other);
}
} /**
* 尝试获取锁对象, 不会阻塞
*
* @throws InterruptedException
* @throws KeeperException
*/
public boolean tryLock() throws KeeperException {
// 可能初始化的时候就失败了
if (exception != null) {
throw exception;
} if (isOwner()) {//锁重入
return true;
} acquireLock(null); if (exception != null) {
throw exception;
} if (interrupt != null) {
Thread.currentThread().interrupt();
} if (other != null) {
throw new NestableRuntimeException(other);
} return isOwner();
} /**
* 释放锁对象
*/
public void unlock() throws KeeperException {
if (id != null) {
try {
zookeeper.delete(root + "/" + id, -1);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (KeeperException.NoNodeException e) {
// do nothing
} finally {
id = null;
}
} else {
//do nothing
}
} private void ensureExists(final String path) {
try {
Stat stat = zookeeper.exists(path, false);
if (stat != null) {
return;
} zookeeper.create(path, data, CreateMode.PERSISTENT);
} catch (KeeperException e) {
exception = e;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
interrupt = e;
}
} /**
* 返回锁对象对应的path
*/
public String getRoot() {
return root;
} /**
* 判断当前是不是锁的owner
*/
public boolean isOwner() {
return id != null && ownerId != null && id.equals(ownerId);
} /**
* 返回当前的节点id
*/
public String getId() {
return this.id;
} // ===================== helper method ============================= /**
* 执行lock操作,允许传递watch变量控制是否需要阻塞lock操作
*/
private Boolean acquireLock(final BooleanMutex mutex) {
try {
do {
if (id == null) {//构建当前lock的唯一标识
long sessionId = zookeeper.getDelegate().getSessionId();
String prefix = "x-" + sessionId + "-";
//如果第一次,则创建一个节点
String path = zookeeper.create(root + "/" + prefix, data,
CreateMode.EPHEMERAL_SEQUENTIAL);
int index = path.lastIndexOf("/");
id = StringUtils.substring(path, index + 1);
idName = new LockNode(id);
} if (id != null) {
List<String> names = zookeeper.getChildren(root, false);
if (names.isEmpty()) {
id = null;//异常情况,重新创建一个
} else {
//对节点进行排序
SortedSet<LockNode> sortedNames = new TreeSet<LockNode>();
for (String name : names) {
sortedNames.add(new LockNode(name));
} if (sortedNames.contains(idName) == false) {
id = null;//清空为null,重新创建一个
continue;
} //将第一个节点做为ownerId
ownerId = sortedNames.first().getName();
if (mutex != null && isOwner()) {
mutex.set(true);//直接更新状态,返回
return true;
} else if (mutex == null) {
return isOwner();
} SortedSet<LockNode> lessThanMe = sortedNames.headSet(idName);
if (!lessThanMe.isEmpty()) {
//关注一下排队在自己之前的最近的一个节点
LockNode lastChildName = lessThanMe.last();
lastChildId = lastChildName.getName();
//异步watcher处理
zookeeper.exists(root + "/" + lastChildId, new AsyncWatcher() { public void asyncProcess(WatchedEvent event) {
acquireLock(mutex);
} }); if (stat == null) {
acquireLock(mutex);// 如果节点不存在,需要自己重新触发一下,watcher不会被挂上去
}
} else {
if (isOwner()) {
mutex.set(true);
} else {
id = null;// 可能自己的节点已超时挂了,所以id和ownerId不相同
}
}
}
}
} while (id == null);
} catch (KeeperException e) {
exception = e;
if (mutex != null) {
mutex.set(true);
}
} catch (InterruptedException e) {
interrupt = e;
if (mutex != null) {
mutex.set(true);
}
} catch (Throwable e) {
other = e;
if (mutex != null) {
mutex.set(true);
}
} if (isOwner() && mutex != null) {
mutex.set(true);
}
return Boolean.FALSE;
}
}

相关说明:

测试代码:

  1. @Test
  2. public void test_lock() {
  3. ExecutorService exeucotr = Executors.newCachedThreadPool();
  4. final int count = 50;
  5. final CountDownLatch latch = new CountDownLatch(count);
  6. final DistributedLock[] nodes = new DistributedLock[count];
  7. for (int i = 0; i < count; i++) {
  8. final DistributedLock node = new DistributedLock(dir);
  9. nodes[i] = node;
  10. exeucotr.submit(new Runnable() {
  11. public void run() {
  12. try {
  13. Thread.sleep(1000);
  14. node.lock(); //获取锁
  15. Thread.sleep(100 + RandomUtils.nextInt(100));
  16. System.out.println("id: " + node.getId() + " is leader: " + node.isOwner());
  17. } catch (InterruptedException e) {
  18. want.fail();
  19. } catch (KeeperException e) {
  20. want.fail();
  21. } finally {
  22. latch.countDown();
  23. try {
  24. node.unlock();
  25. } catch (KeeperException e) {
  26. want.fail();
  27. }
  28. }
  29. }
  30. });
  31. }
  32. try {
  33. latch.await();
  34. } catch (InterruptedException e) {
  35. want.fail();
  36. }
  37. exeucotr.shutdown();
  38. }
@Test
public void test_lock() {
ExecutorService exeucotr = Executors.newCachedThreadPool();
final int count = 50;
final CountDownLatch latch = new CountDownLatch(count);
final DistributedLock[] nodes = new DistributedLock[count];
for (int i = 0; i < count; i++) {
final DistributedLock node = new DistributedLock(dir);
nodes[i] = node;
exeucotr.submit(new Runnable() { public void run() {
try {
Thread.sleep(1000);
node.lock(); //获取锁
Thread.sleep(100 + RandomUtils.nextInt(100)); System.out.println("id: " + node.getId() + " is leader: " + node.isOwner());
} catch (InterruptedException e) {
want.fail();
} catch (KeeperException e) {
want.fail();
} finally {
latch.countDown();
try {
node.unlock();
} catch (KeeperException e) {
want.fail();
}
} }
});
} try {
latch.await();
} catch (InterruptedException e) {
want.fail();
} exeucotr.shutdown();
}

升级版

实现了一个分布式lock后,可以解决多进程之间的同步问题,但设计多线程+多进程的lock控制需求,单jvm中每个线程都和zookeeper进行网络交互成本就有点高了,所以基于DistributedLock,实现了一个分布式二层锁。

大致原理就是ReentrantLock 和 DistributedLock的一个结合。

  • 单jvm的多线程竞争时,首先需要先拿到第一层的ReentrantLock的锁
  • 拿到锁之后这个线程再去和其他JVM的线程竞争锁,最后拿到之后锁之后就开始处理任务。
锁的释放过程是一个反方向的操作,先释放DistributedLock,再释放ReentrantLock。 可以思考一下,如果先释放ReentrantLock,假如这个JVM ReentrantLock竞争度比较高,一直其他JVM的锁竞争容易被饿死。
 
代码:
  1. public class DistributedReentrantLock extends DistributedLock {
  2. private static final String ID_FORMAT     = "Thread[{0}] Distributed[{1}]";
  3. private ReentrantLock       reentrantLock = new ReentrantLock();
  4. public DistributedReentrantLock(String root) {
  5. super(root);
  6. }
  7. public void lock() throws InterruptedException, KeeperException {
  8. reentrantLock.lock();//多线程竞争时,先拿到第一层锁
  9. super.lock();
  10. }
  11. public boolean tryLock() throws KeeperException {
  12. //多线程竞争时,先拿到第一层锁
  13. return reentrantLock.tryLock() && super.tryLock();
  14. }
  15. public void unlock() throws KeeperException {
  16. super.unlock();
  17. reentrantLock.unlock();//多线程竞争时,释放最外层锁
  18. }
  19. @Override
  20. public String getId() {
  21. return MessageFormat.format(ID_FORMAT, Thread.currentThread().getId(), super.getId());
  22. }
  23. @Override
  24. public boolean isOwner() {
  25. return reentrantLock.isHeldByCurrentThread() && super.isOwner();
  26. }
  27. }
public class DistributedReentrantLock extends DistributedLock {

    private static final String ID_FORMAT     = "Thread[{0}] Distributed[{1}]";
private ReentrantLock reentrantLock = new ReentrantLock(); public DistributedReentrantLock(String root) {
super(root);
} public void lock() throws InterruptedException, KeeperException {
reentrantLock.lock();//多线程竞争时,先拿到第一层锁
super.lock();
} public boolean tryLock() throws KeeperException {
//多线程竞争时,先拿到第一层锁
return reentrantLock.tryLock() && super.tryLock();
} public void unlock() throws KeeperException {
super.unlock();
reentrantLock.unlock();//多线程竞争时,释放最外层锁
} @Override
public String getId() {
return MessageFormat.format(ID_FORMAT, Thread.currentThread().getId(), super.getId());
} @Override
public boolean isOwner() {
return reentrantLock.isHeldByCurrentThread() && super.isOwner();
} }
 
测试代码:
  1. @Test
  2. public void test_lock() {
  3. ExecutorService exeucotr = Executors.newCachedThreadPool();
  4. final int count = 50;
  5. final CountDownLatch latch = new CountDownLatch(count);
  6. final DistributedReentrantLock lock = new DistributedReentrantLock(dir); //单个锁
  7. for (int i = 0; i < count; i++) {
  8. exeucotr.submit(new Runnable() {
  9. public void run() {
  10. try {
  11. Thread.sleep(1000);
  12. lock.lock();
  13. Thread.sleep(100 + RandomUtils.nextInt(100));
  14. System.out.println("id: " + lock.getId() + " is leader: " + lock.isOwner());
  15. } catch (InterruptedException e) {
  16. want.fail();
  17. } catch (KeeperException e) {
  18. want.fail();
  19. } finally {
  20. latch.countDown();
  21. try {
  22. lock.unlock();
  23. } catch (KeeperException e) {
  24. want.fail();
  25. }
  26. }
  27. }
  28. });
  29. }
  30. try {
  31. latch.await();
  32. } catch (InterruptedException e) {
  33. want.fail();
  34. }
  35. exeucotr.shutdown();
  36. }
@Test
public void test_lock() {
ExecutorService exeucotr = Executors.newCachedThreadPool();
final int count = 50;
final CountDownLatch latch = new CountDownLatch(count); final DistributedReentrantLock lock = new DistributedReentrantLock(dir); //单个锁
for (int i = 0; i < count; i++) {
exeucotr.submit(new Runnable() { public void run() {
try {
Thread.sleep(1000);
lock.lock();
Thread.sleep(100 + RandomUtils.nextInt(100)); System.out.println("id: " + lock.getId() + " is leader: " + lock.isOwner());
} catch (InterruptedException e) {
want.fail();
} catch (KeeperException e) {
want.fail();
} finally {
latch.countDown();
try {
lock.unlock();
} catch (KeeperException e) {
want.fail();
}
} }
});
} try {
latch.await();
} catch (InterruptedException e) {
want.fail();
} exeucotr.shutdown();
}

最后

其实再可以发散一下,实现一个分布式的read/write lock,也差不多就是这个理了。项目结束后,有时间可以写一下

大致思路:

  1. 竞争资源标示:  read_自增id , write_自增id
  2. 首先按照自增id进行排序,如果队列的前边都是read标识,对应的所有read都获得锁。如果队列的前边是write标识,第一个write节点获取锁
  3. watcher监听: read监听距离自己最近的一个write节点的exist,write监听距离自己最近的一个节点(read或者write节点)
  • 大小: 74.4 KB
分享到:                  
评论
3 楼     agapple    2013-11-18            
accp_huangxin 写道
大哥,能提供一下LockNode这个对象结构吗
  1. public class LockNode implements Comparable<LockNode> {
  2. private final String name;
  3. private String       prefix;
  4. private int          sequence = -1;
  5. public LockNode(String name){
  6. Assert.notNull(name, "id cannot be null");
  7. this.name = name;
  8. this.prefix = name;
  9. int idx = name.lastIndexOf('-');
  10. if (idx >= 0) {
  11. this.prefix = name.substring(0, idx);
  12. try {
  13. this.sequence = Integer.parseInt(name.substring(idx + 1));
  14. } catch (Exception e) {
  15. // ignore
  16. }
  17. }
  18. }
  19. public int compareTo(LockNode that) {
  20. int s1 = this.sequence;
  21. int s2 = that.sequence;
  22. if (s1 == -1 && s2 == -1) {
  23. return this.name.compareTo(that.name);
  24. }
  25. if (s1 == -1) {
  26. return -1;
  27. } else if (s2 == -1) {
  28. return 1;
  29. } else {
  30. return s1 - s2;
  31. }
  32. }
  33. public String getName() {
  34. return name;
  35. }
  36. public int getSequence() {
  37. return sequence;
  38. }
  39. public String getPrefix() {
  40. return prefix;
  41. }
  42. public String toString() {
  43. return name.toString();
  44. }
  45. // ==================== hashcode & equals方法=======================
  46. @Override
  47. public int hashCode() {
  48. final int prime = 31;
  49. int result = 1;
  50. result = prime * result + ((name == null) ? 0 : name.hashCode());
  51. return result;
  52. }
  53. @Override
  54. public boolean equals(Object obj) {
  55. if (this == obj) {
  56. return true;
  57. }
  58. if (obj == null) {
  59. return false;
  60. }
  61. if (getClass() != obj.getClass()) {
  62. return false;
  63. }
  64. LockNode other = (LockNode) obj;
  65. if (name == null) {
  66. if (other.name != null) {
  67. return false;
  68. }
  69. } else if (!name.equals(other.name)) {
  70. return false;
  71. }
  72. return true;
  73. }
  74. }
public class LockNode implements Comparable<LockNode> {

    private final String name;
private String prefix;
private int sequence = -1; public LockNode(String name){
Assert.notNull(name, "id cannot be null");
this.name = name;
this.prefix = name;
int idx = name.lastIndexOf('-');
if (idx >= 0) {
this.prefix = name.substring(0, idx);
try {
this.sequence = Integer.parseInt(name.substring(idx + 1));
} catch (Exception e) {
// ignore
}
}
} public int compareTo(LockNode that) {
int s1 = this.sequence;
int s2 = that.sequence;
if (s1 == -1 && s2 == -1) {
return this.name.compareTo(that.name);
} if (s1 == -1) {
return -1;
} else if (s2 == -1) {
return 1;
} else {
return s1 - s2;
}
} public String getName() {
return name;
} public int getSequence() {
return sequence;
} public String getPrefix() {
return prefix;
} public String toString() {
return name.toString();
} // ==================== hashcode & equals方法======================= @Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
} @Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
LockNode other = (LockNode) obj;
if (name == null) {
if (other.name != null) {
return false;
}
} else if (!name.equals(other.name)) {
return false;
}
return true;
} }
   
 
 

【转载】zookeeper 分布式锁 实现的更多相关文章

  1. [转载] zookeeper 分布式锁服务

    转载自http://www.cnblogs.com/shanyou/archive/2012/09/22/2697818.html 分布式锁服务在大家的项目中或许用的不多,因为大家都把排他放在数据库那 ...

  2. 跟着大神学zookeeper分布式锁实现-----来自Ruthless

    前几天分享了@Ruthless大神的Redis锁,发现和大家都学习了很多东西.因为分布式锁里面,最好的实现是zookeeper的分布式锁.所以在这里把实现方式和大家分享一下. zookeeper分布式 ...

  3. zookeeper分布式锁

    摘要:分享牛原创,zookeeper使用,zookeeper锁在实际项目开发中还是很常用的,在这里我们介绍一下zookeeper分布式锁的使用,以及我们如何zookeeper分布式锁的原理.zooke ...

  4. 分布式锁(一) Zookeeper分布式锁

    什么是Zookeeper? Zookeeper(业界简称zk)是一种提供配置管理.分布式协同以及命名的中心化服务,这些提供的功能都是分布式系统中非常底层且必不可少的基本功能,但是如果自己实现这些功能而 ...

  5. ZooKeeper分布式锁的实现原理

    七张图彻底讲清楚ZooKeeper分布式锁的实现原理[石杉的架构笔记] 文章转载自:https://juejin.im/post/5c01532ef265da61362232ed#comment(写的 ...

  6. ZooKeeper分布式锁的实现

    ZooKeeper分布式锁的实现. 在分布式的情况下,sychornized 和 Lock 已经不能满足我们的要求了,那么就需要使用第三方的锁了,这里我们就使用 ZooKeeper 来实现一个分布式锁 ...

  7. Curator Zookeeper分布式锁

    Curator Zookeeper分布式锁 pom.xml中添加如下配置 <!-- https://mvnrepository.com/artifact/org.apache.curator/c ...

  8. ZooKeeper 分布式锁实现

    1 场景描述 在分布式应用, 往往存在多个进程提供同一服务. 这些进程有可能在相同的机器上, 也有可能分布在不同的机器上. 如果这些进程共享了一些资源, 可能就需要分布式锁来锁定对这些资源的访问. 2 ...

  9. ZooKeeper分布式锁浅谈(一)

    一.概述 清明节的时候写了一篇分布式锁概述,里面介绍了分布式锁实现的几种方式,其实那时候我一直沉迷于使用redis的悲观锁和乐观锁来实现分布式锁,直到一个血案的引发才让我重新认识了redis分布式锁的 ...

  10. 关于分布式锁原理的一些学习与思考-redis分布式锁,zookeeper分布式锁

    首先分布式锁和我们平常讲到的锁原理基本一样,目的就是确保,在多个线程并发时,只有一个线程在同一刻操作这个业务或者说方法.变量. 在一个进程中,也就是一个jvm 或者说应用中,我们很容易去处理控制,在j ...

随机推荐

  1. HDU 4628 Pieces(DP + 状态压缩)

    Pieces 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4628 题目大意:给定一个字符串s,如果子序列中有回文,可以一步删除掉它,求把整个序列删除 ...

  2. Iptables網路連線限制及攻擊防護和相關設定

    [筆記整理]Iptables網路連線限制及攻擊防護和相關設定 1. 限制每個IP連接HTTP最大併發50個連接數 iptables -A INPUT -p tcp --dport 80 -m conn ...

  3. centos 不支持mysql

    感觉是php-odbc必须装 yum -y install php php-fpm yum –y install php-mysql php-common php-mbstring php-gd ph ...

  4. 【原创】Linux编译内核

    Linux 编译内核 大致分这几个步骤 1.准备编译工具.内核文件 2.开始编译 3.将编译好的新内核install进系统 4.查看是否成功.   一.准备好必备的库和内核文件   1.添加必备的编译 ...

  5. css3 标题超过长度自动省略号

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...

  6. c++ 最短路两种算法

    最短路是个老问题了,大神们留下很多文档但是很多都是针对算法使用一些固定大小的数组进行数据存储在实际应用中受到限制,这里自己练习一下,主要用了一些c++的stl,减少了固定长度数组的依赖,换一种写法试图 ...

  7. Ajax、Comet、HTML 5 Web Sockets技术比较分析

    最近因为考虑研究B/S结构网站即时消息处理 参考了 JAVA怎么样实现即时消息提醒http://bbs.csdn.net/topics/330015611http://www.ibm.com/deve ...

  8. 练习--python中的Queue与多进程(multiprocessing)

    按官方说法: This module is OBSOLETE and is only provided on PyPI to support old projects that still use i ...

  9. UIKIT网页基本结构学习

    没办法,哈哈,以后一段时间,如果公司没有招到合适的运维研发, 啥啥都要我一个人先顶上了~~~:) 也好,可以让人成长. UIKIT,BOOTSTRAP之类的前端,搞一个是有好处的,我们以前即然是用了U ...

  10. PHP 文件上传注意一个地方,移动文件时要保证目标目录存在,否则报错

    move_uploaded_file ( $_FILES ["file"] ["tmp_name"], "upload/" . $fileN ...