https://blog.csdn.net/desilting/article/details/41280869

这里利用zookeeper的EPHEMERAL_SEQUENTIAL类型节点及watcher机制,来简单实现分布式锁。

主要思想:
1、开启10个线程,在disLocks节点下各自创建名为sub的EPHEMERAL_SEQUENTIAL节点;
2、获取disLocks节点下所有子节点,排序,如果自己的节点编号最小,则获取锁;
3、否则watch排在自己前面的节点,监听到其删除后,进入第2步(重新检测排序是防止监听的节点发生连接失效,导致的节点删除情况);
4、删除自身sub节点,释放连接;
 
这里插播下zookeeper的4种节点类型:
  1. public enum CreateMode {
  2. /**
  3. * 持久节点:节点创建后,会一直存在,不会因客户端会话失效而删除;
  4. */
  5. PERSISTENT (0, false, false),
  6. /**
  7. * 持久顺序节点:基本特性与持久节点一致,创建节点的过程中,zookeeper会在其名字后自动追加一个单调增长的数字后缀,作为新的节点名;
  8. */
  9. PERSISTENT_SEQUENTIAL (2, false, true),
  10. /**
  11. *  临时节点:客户端会话失效或连接关闭后,该节点会被自动删除,且不能再临时节点下面创建子节点,否则报如下错:org.apache.zookeeper.KeeperException$NoChildrenForEphemeralsException;
  12. */
  13. EPHEMERAL (1, true, false),
  14. /**
  15. * 临时顺序节点:基本特性与临时节点一致,创建节点的过程中,zookeeper会在其名字后自动追加一个单调增长的数字后缀,作为新的节点名;
  16. */
  17. EPHEMERAL_SEQUENTIAL (3, true, true);
  18. private static final Logger LOG = LoggerFactory.getLogger(CreateMode.class);
  19. private boolean ephemeral;
  20. private boolean sequential;
  21. private int flag;
  22. CreateMode(int flag, boolean ephemeral, boolean sequential) {
  23. this.flag = flag;
  24. this.ephemeral = ephemeral;
  25. this.sequential = sequential;
  26. }
  27. public boolean isEphemeral() {
  28. return ephemeral;
  29. }
  30. public boolean isSequential() {
  31. return sequential;
  32. }
  33. public int toFlag() {
  34. return flag;
  35. }
  36. static public CreateMode fromFlag(int flag) throws KeeperException {
  37. switch(flag) {
  38. case 0: return CreateMode.PERSISTENT;
  39. case 1: return CreateMode.EPHEMERAL;
  40. case 2: return CreateMode.PERSISTENT_SEQUENTIAL;
  41. case 3: return CreateMode.EPHEMERAL_SEQUENTIAL ;
  42. default:
  43. LOG.error("Received an invalid flag value to convert to a CreateMode");
  44. throw new KeeperException.BadArgumentsException();
  45. }
  46. }
  47. }
  1. public enum CreateMode {
  2.  
  3. /**
  4. * 持久节点:节点创建后,会一直存在,不会因客户端会话失效而删除;
  5. */
  6. PERSISTENT (0, false, false),
  7.  
  8. /**
  9. * 持久顺序节点:基本特性与持久节点一致,创建节点的过程中,zookeeper会在其名字后自动追加一个单调增长的数字后缀,作为新的节点名;
  10. */
  11. PERSISTENT_SEQUENTIAL (2, false, true),
  12.  
  13. /**
  14. * 临时节点:客户端会话失效或连接关闭后,该节点会被自动删除,且不能再临时节点下面创建子节点,否则报如下错:org.apache.zookeeper.KeeperException$NoChildrenForEphemeralsException;
  15. */
  16. EPHEMERAL (1, true, false),
  17.  
  18. /**
  19. * 临时顺序节点:基本特性与临时节点一致,创建节点的过程中,zookeeper会在其名字后自动追加一个单调增长的数字后缀,作为新的节点名;
  20. */
  21. EPHEMERAL_SEQUENTIAL (3, true, true);
  22. private static final Logger LOG = LoggerFactory.getLogger(CreateMode.class);
  23. private boolean ephemeral;
  24. private boolean sequential;
  25. private int flag;
  26. CreateMode(int flag, boolean ephemeral, boolean sequential) {
  27. this.flag = flag;
  28. this.ephemeral = ephemeral;
  29. this.sequential = sequential;
  30. }
  31. public boolean isEphemeral() {
  32. return ephemeral;
  33. }
  34. public boolean isSequential() {
  35. return sequential;
  36. }
  37. public int toFlag() {
  38. return flag;
  39. }
  40. static public CreateMode fromFlag(int flag) throws KeeperException {
  41. switch(flag) {
  42. case 0: return CreateMode.PERSISTENT;
  43. case 1: return CreateMode.EPHEMERAL;
  44. case 2: return CreateMode.PERSISTENT_SEQUENTIAL;
  45. case 3: return CreateMode.EPHEMERAL_SEQUENTIAL ;
  46. default:
  47. LOG.error("Received an invalid flag value to convert to a CreateMode");
  48. throw new KeeperException.BadArgumentsException();
  49. }
  50. }
  51. }
测试代码:
  1. package zookeeper;
  2. import org.slf4j.Logger;
  3. import org.slf4j.LoggerFactory;
  4. import org.apache.zookeeper.*;
  5. import org.apache.zookeeper.data.Stat;
  6. import java.util.List;
  7. import java.io.IOException;
  8. import java.util.Collections;
  9. import java.util.concurrent.CountDownLatch;
  10. public class DistributedLock implements Watcher{
  11. private int threadId;
  12. private ZooKeeper zk = null;
  13. private String selfPath;
  14. private String waitPath;
  15. private String LOG_PREFIX_OF_THREAD;
  16. private static final int SESSION_TIMEOUT = 10000;
  17. private static final String GROUP_PATH = "/disLocks";
  18. private static final String SUB_PATH = "/disLocks/sub";
  19. private static final String CONNECTION_STRING = "192.168.*.*:2181";
  20. private static final int THREAD_NUM = 10;
  21. //确保连接zk成功;
  22. private CountDownLatch connectedSemaphore = new CountDownLatch(1);
  23. //确保所有线程运行结束;
  24. private static final CountDownLatch threadSemaphore = new CountDownLatch(THREAD_NUM);
  25. private static final Logger LOG = LoggerFactory.getLogger(AllZooKeeperWatcher.class);
  26. public DistributedLock(int id) {
  27. this.threadId = id;
  28. LOG_PREFIX_OF_THREAD = "【第"+threadId+"个线程】";
  29. }
  30. public static void main(String[] args) {
  31. for(int i=0; i < THREAD_NUM; i++){
  32. final int threadId = i+1;
  33. new Thread(){
  34. @Override
  35. public void run() {
  36. try{
  37. DistributedLock dc = new DistributedLock(threadId);
  38. dc.createConnection(CONNECTION_STRING, SESSION_TIMEOUT);
  39. //GROUP_PATH不存在的话,由一个线程创建即可;
  40. synchronized (threadSemaphore){
  41. dc.createPath(GROUP_PATH, "该节点由线程" + threadId + "创建", true);
  42. }
  43. dc.getLock();
  44. } catch (Exception e){
  45. LOG.error("【第"+threadId+"个线程】 抛出的异常:");
  46. e.printStackTrace();
  47. }
  48. }
  49. }.start();
  50. }
  51. try {
  52. threadSemaphore.await();
  53. LOG.info("所有线程运行结束!");
  54. } catch (InterruptedException e) {
  55. e.printStackTrace();
  56. }
  57. }
  58. /**
  59. * 获取锁
  60. * @return
  61. */
  62. private void getLock() throws KeeperException, InterruptedException {
  63. selfPath = zk.create(SUB_PATH,null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
  64. LOG.info(LOG_PREFIX_OF_THREAD+"创建锁路径:"+selfPath);
  65. if(checkMinPath()){
  66. getLockSuccess();
  67. }
  68. }
  69. /**
  70. * 创建节点
  71. * @param path 节点path
  72. * @param data 初始数据内容
  73. * @return
  74. */
  75. public boolean createPath( String path, String data, boolean needWatch) throws KeeperException, InterruptedException {
  76. if(zk.exists(path, needWatch)==null){
  77. LOG.info( LOG_PREFIX_OF_THREAD + "节点创建成功, Path: "
  78. + this.zk.create( path,
  79. data.getBytes(),
  80. ZooDefs.Ids.OPEN_ACL_UNSAFE,
  81. CreateMode.PERSISTENT )
  82. + ", content: " + data );
  83. }
  84. return true;
  85. }
  86. /**
  87. * 创建ZK连接
  88. * @param connectString  ZK服务器地址列表
  89. * @param sessionTimeout Session超时时间
  90. */
  91. public void createConnection( String connectString, int sessionTimeout ) throws IOException, InterruptedException {
  92. zk = new ZooKeeper( connectString, sessionTimeout, this);
  93. connectedSemaphore.await();
  94. }
  95. /**
  96. * 获取锁成功
  97. */
  98. public void getLockSuccess() throws KeeperException, InterruptedException {
  99. if(zk.exists(this.selfPath,false) == null){
  100. LOG.error(LOG_PREFIX_OF_THREAD+"本节点已不在了...");
  101. return;
  102. }
  103. LOG.info(LOG_PREFIX_OF_THREAD + "获取锁成功,赶紧干活!");
  104. Thread.sleep(2000);
  105. LOG.info(LOG_PREFIX_OF_THREAD + "删除本节点:"+selfPath);
  106. zk.delete(this.selfPath, -1);
  107. releaseConnection();
  108. threadSemaphore.countDown();
  109. }
  110. /**
  111. * 关闭ZK连接
  112. */
  113. public void releaseConnection() {
  114. if ( this.zk !=null ) {
  115. try {
  116. this.zk.close();
  117. } catch ( InterruptedException e ) {}
  118. }
  119. LOG.info(LOG_PREFIX_OF_THREAD + "释放连接");
  120. }
  121. /**
  122. * 检查自己是不是最小的节点
  123. * @return
  124. */
  125. public boolean checkMinPath() throws KeeperException, InterruptedException {
  126. List<String> subNodes = zk.getChildren(GROUP_PATH, false);
  127. Collections.sort(subNodes);
  128. int index = subNodes.indexOf( selfPath.substring(GROUP_PATH.length()+1));
  129. switch (index){
  130. case -1:{
  131. LOG.error(LOG_PREFIX_OF_THREAD+"本节点已不在了..."+selfPath);
  132. return false;
  133. }
  134. case 0:{
  135. LOG.info(LOG_PREFIX_OF_THREAD+"子节点中,我果然是老大"+selfPath);
  136. return true;
  137. }
  138. default:{
  139. this.waitPath = GROUP_PATH +"/"+ subNodes.get(index - 1);
  140. LOG.info(LOG_PREFIX_OF_THREAD+"获取子节点中,排在我前面的"+waitPath);
  141. try{
  142. zk.getData(waitPath, true, new Stat());
  143. return false;
  144. }catch(KeeperException e){
  145. if(zk.exists(waitPath,false) == null){
  146. LOG.info(LOG_PREFIX_OF_THREAD+"子节点中,排在我前面的"+waitPath+"已失踪,幸福来得太突然?");
  147. return checkMinPath();
  148. }else{
  149. throw e;
  150. }
  151. }
  152. }
  153. }
  154. }
  155. @Override
  156. public void process(WatchedEvent event) {
  157. if(event == null){
  158. return;
  159. }
  160. Event.KeeperState keeperState = event.getState();
  161. Event.EventType eventType = event.getType();
  162. if ( Event.KeeperState.SyncConnected == keeperState) {
  163. if ( Event.EventType.None == eventType ) {
  164. LOG.info( LOG_PREFIX_OF_THREAD + "成功连接上ZK服务器" );
  165. connectedSemaphore.countDown();
  166. }else if (event.getType() == Event.EventType.NodeDeleted && event.getPath().equals(waitPath)) {
  167. LOG.info(LOG_PREFIX_OF_THREAD + "收到情报,排我前面的家伙已挂,我是不是可以出山了?");
  168. try {
  169. if(checkMinPath()){
  170. getLockSuccess();
  171. }
  172. } catch (KeeperException e) {
  173. e.printStackTrace();
  174. } catch (InterruptedException e) {
  175. e.printStackTrace();
  176. }
  177. }
  178. }else if ( Event.KeeperState.Disconnected == keeperState ) {
  179. LOG.info( LOG_PREFIX_OF_THREAD + "与ZK服务器断开连接" );
  180. } else if ( Event.KeeperState.AuthFailed == keeperState ) {
  181. LOG.info( LOG_PREFIX_OF_THREAD + "权限检查失败" );
  182. } else if ( Event.KeeperState.Expired == keeperState ) {
  183. LOG.info( LOG_PREFIX_OF_THREAD + "会话失效" );
  184. }
  185. }
  186. }
  1. package zookeeper;
  2. import org.slf4j.Logger;
  3. import org.slf4j.LoggerFactory;
  4. import org.apache.zookeeper.*;
  5. import org.apache.zookeeper.data.Stat;
  6. import java.util.List;
  7. import java.io.IOException;
  8. import java.util.Collections;
  9. import java.util.concurrent.CountDownLatch;
  10.  
  11. public class DistributedLock implements Watcher{
  12. private int threadId;
  13. private ZooKeeper zk = null;
  14. private String selfPath;
  15. private String waitPath;
  16. private String LOG_PREFIX_OF_THREAD;
  17. private static final int SESSION_TIMEOUT = 10000;
  18. private static final String GROUP_PATH = "/disLocks";
  19. private static final String SUB_PATH = "/disLocks/sub";
  20. private static final String CONNECTION_STRING = "192.168.*.*:2181";
  21.  
  22. private static final int THREAD_NUM = 10;
  23. //确保连接zk成功;
  24. private CountDownLatch connectedSemaphore = new CountDownLatch(1);
  25. //确保所有线程运行结束;
  26. private static final CountDownLatch threadSemaphore = new CountDownLatch(THREAD_NUM);
  27. private static final Logger LOG = LoggerFactory.getLogger(AllZooKeeperWatcher.class);
  28. public DistributedLock(int id) {
  29. this.threadId = id;
  30. LOG_PREFIX_OF_THREAD = "【第"+threadId+"个线程】";
  31. }
  32. public static void main(String[] args) {
  33. for(int i=0; i < THREAD_NUM; i++){
  34. final int threadId = i+1;
  35. new Thread(){
  36. @Override
  37. public void run() {
  38. try{
  39. DistributedLock dc = new DistributedLock(threadId);
  40. dc.createConnection(CONNECTION_STRING, SESSION_TIMEOUT);
  41. //GROUP_PATH不存在的话,由一个线程创建即可;
  42. synchronized (threadSemaphore){
  43. dc.createPath(GROUP_PATH, "该节点由线程" + threadId + "创建", true);
  44. }
  45. dc.getLock();
  46. } catch (Exception e){
  47. LOG.error("【第"+threadId+"个线程】 抛出的异常:");
  48. e.printStackTrace();
  49. }
  50. }
  51. }.start();
  52. }
  53. try {
  54. threadSemaphore.await();
  55. LOG.info("所有线程运行结束!");
  56. } catch (InterruptedException e) {
  57. e.printStackTrace();
  58. }
  59. }
  60. /**
  61. * 获取锁
  62. * @return
  63. */
  64. private void getLock() throws KeeperException, InterruptedException {
  65. selfPath = zk.create(SUB_PATH,null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
  66. LOG.info(LOG_PREFIX_OF_THREAD+"创建锁路径:"+selfPath);
  67. if(checkMinPath()){
  68. getLockSuccess();
  69. }
  70. }
  71. /**
  72. * 创建节点
  73. * @param path 节点path
  74. * @param data 初始数据内容
  75. * @return
  76. */
  77. public boolean createPath( String path, String data, boolean needWatch) throws KeeperException, InterruptedException {
  78. if(zk.exists(path, needWatch)==null){
  79. LOG.info( LOG_PREFIX_OF_THREAD + "节点创建成功, Path: "
  80. + this.zk.create( path,
  81. data.getBytes(),
  82. ZooDefs.Ids.OPEN_ACL_UNSAFE,
  83. CreateMode.PERSISTENT )
  84. + ", content: " + data );
  85. }
  86. return true;
  87. }
  88. /**
  89. * 创建ZK连接
  90. * @param connectString ZK服务器地址列表
  91. * @param sessionTimeout Session超时时间
  92. */
  93. public void createConnection( String connectString, int sessionTimeout ) throws IOException, InterruptedException {
  94. zk = new ZooKeeper( connectString, sessionTimeout, this);
  95. connectedSemaphore.await();
  96. }
  97. /**
  98. * 获取锁成功
  99. */
  100. public void getLockSuccess() throws KeeperException, InterruptedException {
  101. if(zk.exists(this.selfPath,false) == null){
  102. LOG.error(LOG_PREFIX_OF_THREAD+"本节点已不在了...");
  103. return;
  104. }
  105. LOG.info(LOG_PREFIX_OF_THREAD + "获取锁成功,赶紧干活!");
  106. Thread.sleep(2000);
  107. LOG.info(LOG_PREFIX_OF_THREAD + "删除本节点:"+selfPath);
  108. zk.delete(this.selfPath, -1);
  109. releaseConnection();
  110. threadSemaphore.countDown();
  111. }
  112. /**
  113. * 关闭ZK连接
  114. */
  115. public void releaseConnection() {
  116. if ( this.zk !=null ) {
  117. try {
  118. this.zk.close();
  119. } catch ( InterruptedException e ) {}
  120. }
  121. LOG.info(LOG_PREFIX_OF_THREAD + "释放连接");
  122. }
  123. /**
  124. * 检查自己是不是最小的节点
  125. * @return
  126. */
  127. public boolean checkMinPath() throws KeeperException, InterruptedException {
  128. List<String> subNodes = zk.getChildren(GROUP_PATH, false);
  129. Collections.sort(subNodes);
  130. int index = subNodes.indexOf( selfPath.substring(GROUP_PATH.length()+1));
  131. switch (index){
  132. case -1:{
  133. LOG.error(LOG_PREFIX_OF_THREAD+"本节点已不在了..."+selfPath);
  134. return false;
  135. }
  136. case 0:{
  137. LOG.info(LOG_PREFIX_OF_THREAD+"子节点中,我果然是老大"+selfPath);
  138. return true;
  139. }
  140. default:{
  141. this.waitPath = GROUP_PATH +"/"+ subNodes.get(index - 1);
  142. LOG.info(LOG_PREFIX_OF_THREAD+"获取子节点中,排在我前面的"+waitPath);
  143. try{
  144. zk.getData(waitPath, true, new Stat());
  145. return false;
  146. }catch(KeeperException e){
  147. if(zk.exists(waitPath,false) == null){
  148. LOG.info(LOG_PREFIX_OF_THREAD+"子节点中,排在我前面的"+waitPath+"已失踪,幸福来得太突然?");
  149. return checkMinPath();
  150. }else{
  151. throw e;
  152. }
  153. }
  154. }
  155.  
  156. }
  157.  
  158. }
  159. @Override
  160. public void process(WatchedEvent event) {
  161. if(event == null){
  162. return;
  163. }
  164. Event.KeeperState keeperState = event.getState();
  165. Event.EventType eventType = event.getType();
  166. if ( Event.KeeperState.SyncConnected == keeperState) {
  167. if ( Event.EventType.None == eventType ) {
  168. LOG.info( LOG_PREFIX_OF_THREAD + "成功连接上ZK服务器" );
  169. connectedSemaphore.countDown();
  170. }else if (event.getType() == Event.EventType.NodeDeleted && event.getPath().equals(waitPath)) {
  171. LOG.info(LOG_PREFIX_OF_THREAD + "收到情报,排我前面的家伙已挂,我是不是可以出山了?");
  172. try {
  173. if(checkMinPath()){
  174. getLockSuccess();
  175. }
  176. } catch (KeeperException e) {
  177. e.printStackTrace();
  178. } catch (InterruptedException e) {
  179. e.printStackTrace();
  180. }
  181. }
  182. }else if ( Event.KeeperState.Disconnected == keeperState ) {
  183. LOG.info( LOG_PREFIX_OF_THREAD + "与ZK服务器断开连接" );
  184. } else if ( Event.KeeperState.AuthFailed == keeperState ) {
  185. LOG.info( LOG_PREFIX_OF_THREAD + "权限检查失败" );
  186. } else if ( Event.KeeperState.Expired == keeperState ) {
  187. LOG.info( LOG_PREFIX_OF_THREAD + "会话失效" );
  188. }
  189. }
  190. }

log配置文件:

  1. # DEFAULT
  2. log4j.rootLogger=INFO,CONSOLE
  3. #
  4. # Log INFO level and above messages to the console
  5. #
  6. log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
  7. log4j.appender.CONSOLE.Threshold=INFO
  8. log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
  9. log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} - %m%n
  10. log4j.appender.COMMONSTAT=org.apache.log4j.DailyRollingFileAppender
  11. log4j.appender.COMMONSTAT.Threshold=INFO
  12. log4j.appender.COMMONSTAT.File=/home/zookeeper/zookeeper-test-agent/logs/test.log
  13. log4j.appender.COMMONSTAT.DatePattern='.'yyyy-MM-dd
  14. log4j.appender.COMMONSTAT.layout=org.apache.log4j.PatternLayout
  15. log4j.appender.COMMONSTAT.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}] - %m%n
  16. log4j.logger.org.displaytag=WARN
  17. log4j.logger.org.apache.zookeeper=ERROR
  18. log4j.logger.org.springframework=WARN
  19. log4j.logger.org.I0Itec=WARN
  20. log4j.logger.commonStat=INFO,COMMONSTAT
  1. # DEFAULT
  2. log4j.rootLogger=INFO,CONSOLE
  3.  
  4. #
  5. # Log INFO level and above messages to the console
  6. #
  7. log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
  8. log4j.appender.CONSOLE.Threshold=INFO
  9. log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
  10. log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} - %m%n
  11.  
  12. log4j.appender.COMMONSTAT=org.apache.log4j.DailyRollingFileAppender
  13. log4j.appender.COMMONSTAT.Threshold=INFO
  14. log4j.appender.COMMONSTAT.File=/home/zookeeper/zookeeper-test-agent/logs/test.log
  15. log4j.appender.COMMONSTAT.DatePattern='.'yyyy-MM-dd
  16.  
  17. log4j.appender.COMMONSTAT.layout=org.apache.log4j.PatternLayout
  18. log4j.appender.COMMONSTAT.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}] - %m%n
  19.  
  20. log4j.logger.org.displaytag=WARN
  21. log4j.logger.org.apache.zookeeper=ERROR
  22. log4j.logger.org.springframework=WARN
  23. log4j.logger.org.I0Itec=WARN
  24. log4j.logger.commonStat=INFO,COMMONSTAT

运行结果:

  1. 2014-11-19 11:34:10,894 - 【第9个线程】成功连接上ZK服务器
  2. 2014-11-19 11:34:10,895 - 【第8个线程】成功连接上ZK服务器
  3. 2014-11-19 11:34:10,894 - 【第1个线程】成功连接上ZK服务器
  4. 2014-11-19 11:34:10,894 - 【第7个线程】成功连接上ZK服务器
  5. 2014-11-19 11:34:10,894 - 【第4个线程】成功连接上ZK服务器
  6. 2014-11-19 11:34:10,895 - 【第5个线程】成功连接上ZK服务器
  7. 2014-11-19 11:34:10,896 - 【第2个线程】成功连接上ZK服务器
  8. 2014-11-19 11:34:10,894 - 【第10个线程】成功连接上ZK服务器
  9. 2014-11-19 11:34:10,894 - 【第3个线程】成功连接上ZK服务器
  10. 2014-11-19 11:34:10,895 - 【第6个线程】成功连接上ZK服务器
  11. 2014-11-19 11:34:10,910 - 【第9个线程】节点创建成功, Path: /disLocks, content: 该节点由线程9创建
  12. 2014-11-19 11:34:10,912 - 【第9个线程】创建锁路径:/disLocks/sub0000000000
  13. 2014-11-19 11:34:10,917 - 【第6个线程】创建锁路径:/disLocks/sub0000000001
  14. 2014-11-19 11:34:10,917 - 【第9个线程】子节点中,我果然是老大/disLocks/sub0000000000
  15. 2014-11-19 11:34:10,921 - 【第3个线程】创建锁路径:/disLocks/sub0000000002
  16. 2014-11-19 11:34:10,922 - 【第6个线程】获取子节点中,排在我前面的/disLocks/sub0000000000
  17. 2014-11-19 11:34:10,923 - 【第9个线程】获取锁成功,赶紧干活!
  18. 2014-11-19 11:34:10,924 - 【第10个线程】创建锁路径:/disLocks/sub0000000003
  19. 2014-11-19 11:34:10,924 - 【第3个线程】获取子节点中,排在我前面的/disLocks/sub0000000001
  20. 2014-11-19 11:34:10,928 - 【第10个线程】获取子节点中,排在我前面的/disLocks/sub0000000002
  21. 2014-11-19 11:34:10,929 - 【第1个线程】创建锁路径:/disLocks/sub0000000004
  22. 2014-11-19 11:34:10,932 - 【第5个线程】创建锁路径:/disLocks/sub0000000005
  23. 2014-11-19 11:34:10,935 - 【第1个线程】获取子节点中,排在我前面的/disLocks/sub0000000003
  24. 2014-11-19 11:34:10,936 - 【第2个线程】创建锁路径:/disLocks/sub0000000006
  25. 2014-11-19 11:34:10,936 - 【第5个线程】获取子节点中,排在我前面的/disLocks/sub0000000004
  26. 2014-11-19 11:34:10,940 - 【第4个线程】创建锁路径:/disLocks/sub0000000007
  27. 2014-11-19 11:34:10,941 - 【第2个线程】获取子节点中,排在我前面的/disLocks/sub0000000005
  28. 2014-11-19 11:34:10,943 - 【第8个线程】创建锁路径:/disLocks/sub0000000008
  29. 2014-11-19 11:34:10,944 - 【第4个线程】获取子节点中,排在我前面的/disLocks/sub0000000006
  30. 2014-11-19 11:34:10,945 - 【第7个线程】创建锁路径:/disLocks/sub0000000009
  31. 2014-11-19 11:34:10,946 - 【第8个线程】获取子节点中,排在我前面的/disLocks/sub0000000007
  32. 2014-11-19 11:34:10,947 - 【第7个线程】获取子节点中,排在我前面的/disLocks/sub0000000008
  33. 2014-11-19 11:34:12,923 - 【第9个线程】删除本节点:/disLocks/sub0000000000
  34. 2014-11-19 11:34:12,926 - 【第6个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
  35. 2014-11-19 11:34:12,928 - 【第6个线程】子节点中,我果然是老大/disLocks/sub0000000001
  36. 2014-11-19 11:34:12,930 - 【第9个线程】释放连接
  37. 2014-11-19 11:34:12,930 - 【第6个线程】获取锁成功,赶紧干活!
  38. 2014-11-19 11:34:14,930 - 【第6个线程】删除本节点:/disLocks/sub0000000001
  39. 2014-11-19 11:34:14,937 - 【第3个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
  40. 2014-11-19 11:34:14,941 - 【第3个线程】子节点中,我果然是老大/disLocks/sub0000000002
  41. 2014-11-19 11:34:14,943 - 【第6个线程】释放连接
  42. 2014-11-19 11:34:14,946 - 【第3个线程】获取锁成功,赶紧干活!
  43. 2014-11-19 11:34:16,946 - 【第3个线程】删除本节点:/disLocks/sub0000000002
  44. 2014-11-19 11:34:16,949 - 【第10个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
  45. 2014-11-19 11:34:16,951 - 【第10个线程】子节点中,我果然是老大/disLocks/sub0000000003
  46. 2014-11-19 11:34:16,953 - 【第3个线程】释放连接
  47. 2014-11-19 11:34:16,953 - 【第10个线程】获取锁成功,赶紧干活!
  48. 2014-11-19 11:34:18,953 - 【第10个线程】删除本节点:/disLocks/sub0000000003
  49. 2014-11-19 11:34:18,957 - 【第1个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
  50. 2014-11-19 11:34:18,960 - 【第10个线程】释放连接
  51. 2014-11-19 11:34:18,961 - 【第1个线程】子节点中,我果然是老大/disLocks/sub0000000004
  52. 2014-11-19 11:34:18,964 - 【第1个线程】获取锁成功,赶紧干活!
  53. 2014-11-19 11:34:20,964 - 【第1个线程】删除本节点:/disLocks/sub0000000004
  54. 2014-11-19 11:34:20,967 - 【第5个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
  55. 2014-11-19 11:34:20,969 - 【第5个线程】子节点中,我果然是老大/disLocks/sub0000000005
  56. 2014-11-19 11:34:20,971 - 【第1个线程】释放连接
  57. 2014-11-19 11:34:20,971 - 【第5个线程】获取锁成功,赶紧干活!
  58. 2014-11-19 11:34:22,971 - 【第5个线程】删除本节点:/disLocks/sub0000000005
  59. 2014-11-19 11:34:22,974 - 【第2个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
  60. 2014-11-19 11:34:22,978 - 【第2个线程】子节点中,我果然是老大/disLocks/sub0000000006
  61. 2014-11-19 11:34:22,979 - 【第5个线程】释放连接
  62. 2014-11-19 11:34:22,981 - 【第2个线程】获取锁成功,赶紧干活!
  63. 2014-11-19 11:34:24,981 - 【第2个线程】删除本节点:/disLocks/sub0000000006
  64. 2014-11-19 11:34:24,985 - 【第4个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
  65. 2014-11-19 11:34:24,989 - 【第2个线程】释放连接
  66. 2014-11-19 11:34:24,989 - 【第4个线程】子节点中,我果然是老大/disLocks/sub0000000007
  67. 2014-11-19 11:34:24,995 - 【第4个线程】获取锁成功,赶紧干活!
  68. 2014-11-19 11:34:26,995 - 【第4个线程】删除本节点:/disLocks/sub0000000007
  69. 2014-11-19 11:34:26,998 - 【第8个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
  70. 2014-11-19 11:34:27,000 - 【第8个线程】子节点中,我果然是老大/disLocks/sub0000000008
  71. 2014-11-19 11:34:27,004 - 【第8个线程】获取锁成功,赶紧干活!
  72. 2014-11-19 11:34:27,004 - 【第4个线程】释放连接
  73. 2014-11-19 11:34:29,004 - 【第8个线程】删除本节点:/disLocks/sub0000000008
  74. 2014-11-19 11:34:29,007 - 【第7个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
  75. 2014-11-19 11:34:29,009 - 【第7个线程】子节点中,我果然是老大/disLocks/sub0000000009
  76. 2014-11-19 11:34:29,010 - 【第8个线程】释放连接
  77. 2014-11-19 11:34:29,011 - 【第7个线程】获取锁成功,赶紧干活!
  78. 2014-11-19 11:34:31,011 - 【第7个线程】删除本节点:/disLocks/sub0000000009
  79. 2014-11-19 11:34:31,017 - 【第7个线程】释放连接
  80. 2014-11-19 11:34:31,017 - 所有线程运行结束!
  1. 2014-11-19 11:34:10,894 - 【第9个线程】成功连接上ZK服务器
  2. 2014-11-19 11:34:10,895 - 【第8个线程】成功连接上ZK服务器
  3. 2014-11-19 11:34:10,894 - 【第1个线程】成功连接上ZK服务器
  4. 2014-11-19 11:34:10,894 - 【第7个线程】成功连接上ZK服务器
  5. 2014-11-19 11:34:10,894 - 【第4个线程】成功连接上ZK服务器
  6. 2014-11-19 11:34:10,895 - 【第5个线程】成功连接上ZK服务器
  7. 2014-11-19 11:34:10,896 - 【第2个线程】成功连接上ZK服务器
  8. 2014-11-19 11:34:10,894 - 【第10个线程】成功连接上ZK服务器
  9. 2014-11-19 11:34:10,894 - 【第3个线程】成功连接上ZK服务器
  10. 2014-11-19 11:34:10,895 - 【第6个线程】成功连接上ZK服务器
  11. 2014-11-19 11:34:10,910 - 【第9个线程】节点创建成功, Path: /disLocks, content: 该节点由线程9创建
  12. 2014-11-19 11:34:10,912 - 【第9个线程】创建锁路径:/disLocks/sub0000000000
  13. 2014-11-19 11:34:10,917 - 【第6个线程】创建锁路径:/disLocks/sub0000000001
  14. 2014-11-19 11:34:10,917 - 【第9个线程】子节点中,我果然是老大/disLocks/sub0000000000
  15. 2014-11-19 11:34:10,921 - 【第3个线程】创建锁路径:/disLocks/sub0000000002
  16. 2014-11-19 11:34:10,922 - 【第6个线程】获取子节点中,排在我前面的/disLocks/sub0000000000
  17. 2014-11-19 11:34:10,923 - 【第9个线程】获取锁成功,赶紧干活!
  18. 2014-11-19 11:34:10,924 - 【第10个线程】创建锁路径:/disLocks/sub0000000003
  19. 2014-11-19 11:34:10,924 - 【第3个线程】获取子节点中,排在我前面的/disLocks/sub0000000001
  20. 2014-11-19 11:34:10,928 - 【第10个线程】获取子节点中,排在我前面的/disLocks/sub0000000002
  21. 2014-11-19 11:34:10,929 - 【第1个线程】创建锁路径:/disLocks/sub0000000004
  22. 2014-11-19 11:34:10,932 - 【第5个线程】创建锁路径:/disLocks/sub0000000005
  23. 2014-11-19 11:34:10,935 - 【第1个线程】获取子节点中,排在我前面的/disLocks/sub0000000003
  24. 2014-11-19 11:34:10,936 - 【第2个线程】创建锁路径:/disLocks/sub0000000006
  25. 2014-11-19 11:34:10,936 - 【第5个线程】获取子节点中,排在我前面的/disLocks/sub0000000004
  26. 2014-11-19 11:34:10,940 - 【第4个线程】创建锁路径:/disLocks/sub0000000007
  27. 2014-11-19 11:34:10,941 - 【第2个线程】获取子节点中,排在我前面的/disLocks/sub0000000005
  28. 2014-11-19 11:34:10,943 - 【第8个线程】创建锁路径:/disLocks/sub0000000008
  29. 2014-11-19 11:34:10,944 - 【第4个线程】获取子节点中,排在我前面的/disLocks/sub0000000006
  30. 2014-11-19 11:34:10,945 - 【第7个线程】创建锁路径:/disLocks/sub0000000009
  31. 2014-11-19 11:34:10,946 - 【第8个线程】获取子节点中,排在我前面的/disLocks/sub0000000007
  32. 2014-11-19 11:34:10,947 - 【第7个线程】获取子节点中,排在我前面的/disLocks/sub0000000008
  33. 2014-11-19 11:34:12,923 - 【第9个线程】删除本节点:/disLocks/sub0000000000
  34. 2014-11-19 11:34:12,926 - 【第6个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
  35. 2014-11-19 11:34:12,928 - 【第6个线程】子节点中,我果然是老大/disLocks/sub0000000001
  36. 2014-11-19 11:34:12,930 - 【第9个线程】释放连接
  37. 2014-11-19 11:34:12,930 - 【第6个线程】获取锁成功,赶紧干活!
  38. 2014-11-19 11:34:14,930 - 【第6个线程】删除本节点:/disLocks/sub0000000001
  39. 2014-11-19 11:34:14,937 - 【第3个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
  40. 2014-11-19 11:34:14,941 - 【第3个线程】子节点中,我果然是老大/disLocks/sub0000000002
  41. 2014-11-19 11:34:14,943 - 【第6个线程】释放连接
  42. 2014-11-19 11:34:14,946 - 【第3个线程】获取锁成功,赶紧干活!
  43. 2014-11-19 11:34:16,946 - 【第3个线程】删除本节点:/disLocks/sub0000000002
  44. 2014-11-19 11:34:16,949 - 【第10个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
  45. 2014-11-19 11:34:16,951 - 【第10个线程】子节点中,我果然是老大/disLocks/sub0000000003
  46. 2014-11-19 11:34:16,953 - 【第3个线程】释放连接
  47. 2014-11-19 11:34:16,953 - 【第10个线程】获取锁成功,赶紧干活!
  48. 2014-11-19 11:34:18,953 - 【第10个线程】删除本节点:/disLocks/sub0000000003
  49. 2014-11-19 11:34:18,957 - 【第1个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
  50. 2014-11-19 11:34:18,960 - 【第10个线程】释放连接
  51. 2014-11-19 11:34:18,961 - 【第1个线程】子节点中,我果然是老大/disLocks/sub0000000004
  52. 2014-11-19 11:34:18,964 - 【第1个线程】获取锁成功,赶紧干活!
  53. 2014-11-19 11:34:20,964 - 【第1个线程】删除本节点:/disLocks/sub0000000004
  54. 2014-11-19 11:34:20,967 - 【第5个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
  55. 2014-11-19 11:34:20,969 - 【第5个线程】子节点中,我果然是老大/disLocks/sub0000000005
  56. 2014-11-19 11:34:20,971 - 【第1个线程】释放连接
  57. 2014-11-19 11:34:20,971 - 【第5个线程】获取锁成功,赶紧干活!
  58. 2014-11-19 11:34:22,971 - 【第5个线程】删除本节点:/disLocks/sub0000000005
  59. 2014-11-19 11:34:22,974 - 【第2个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
  60. 2014-11-19 11:34:22,978 - 【第2个线程】子节点中,我果然是老大/disLocks/sub0000000006
  61. 2014-11-19 11:34:22,979 - 【第5个线程】释放连接
  62. 2014-11-19 11:34:22,981 - 【第2个线程】获取锁成功,赶紧干活!
  63. 2014-11-19 11:34:24,981 - 【第2个线程】删除本节点:/disLocks/sub0000000006
  64. 2014-11-19 11:34:24,985 - 【第4个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
  65. 2014-11-19 11:34:24,989 - 【第2个线程】释放连接
  66. 2014-11-19 11:34:24,989 - 【第4个线程】子节点中,我果然是老大/disLocks/sub0000000007
  67. 2014-11-19 11:34:24,995 - 【第4个线程】获取锁成功,赶紧干活!
  68. 2014-11-19 11:34:26,995 - 【第4个线程】删除本节点:/disLocks/sub0000000007
  69. 2014-11-19 11:34:26,998 - 【第8个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
  70. 2014-11-19 11:34:27,000 - 【第8个线程】子节点中,我果然是老大/disLocks/sub0000000008
  71. 2014-11-19 11:34:27,004 - 【第8个线程】获取锁成功,赶紧干活!
  72. 2014-11-19 11:34:27,004 - 【第4个线程】释放连接
  73. 2014-11-19 11:34:29,004 - 【第8个线程】删除本节点:/disLocks/sub0000000008
  74. 2014-11-19 11:34:29,007 - 【第7个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
  75. 2014-11-19 11:34:29,009 - 【第7个线程】子节点中,我果然是老大/disLocks/sub0000000009
  76. 2014-11-19 11:34:29,010 - 【第8个线程】释放连接
  77. 2014-11-19 11:34:29,011 - 【第7个线程】获取锁成功,赶紧干活!
  78. 2014-11-19 11:34:31,011 - 【第7个线程】删除本节点:/disLocks/sub0000000009
  79. 2014-11-19 11:34:31,017 - 【第7个线程】释放连接
  80. 2014-11-19 11:34:31,017 - 所有线程运行结束!

基于zookeeper简单实现分布式锁的更多相关文章

  1. 基于zookeeper实现的分布式锁

    基于zookeeper实现的分布式锁 2011-01-27 • 技术 • 7 条评论 • jiacheo •14,941 阅读 A distributed lock base on zookeeper ...

  2. 利用ZooKeeper简单实现分布式锁

    1.分布式锁的由来: 在程序开发过程中不得不考虑的就是并发问题.在java中对于同一个jvm而言,jdk已经提供了lock和同步等.但是在分布式情况下,往往存在多个进程对一些资源产生竞争关系,而这些进 ...

  3. 基于Zookeeper实现多进程分布式锁

    一.zookeeper简介及基本操作 Zookeeper 并不是用来专门存储数据的,它的作用主要是用来维护和监控你存储的数据的状态变化.当对目录节点监控状态打开时,一旦目录节点的状态发生变化,Watc ...

  4. 基于zookeeper实现高性能分布式锁

    实现原理:利用zookeeper的持久性节点和Watcher机制 具体步骤: 1.创建持久性节点 zkLock 2.在此父节点下创建子节点列表,name按顺序定义 3.Java程序获取该节点下的所有顺 ...

  5. SpringBoot基于数据库实现简单的分布式锁

    本文介绍SpringBoot基于数据库实现简单的分布式锁. 1.简介 分布式锁的方式有很多种,通常方案有: 基于mysql数据库 基于redis 基于ZooKeeper 网上的实现方式有很多,本文主要 ...

  6. 基于 Redis 实现简单的分布式锁

    摘要 分布式锁在很多应用场景下是非常有效的手段,比如当运行在多个机器上的不同进程需要访问同一个竞争资源的时候,那么就会涉及到进程对资源的加锁和释放,这样才能保证数据的安全访问.分布式锁实现的方案有很多 ...

  7. 基于Redis实现简单的分布式锁【理论】

    摘要 分布式锁在很多应用场景下是非常有效的手段,比如当运行在多个机器上的不同进程需要访问同一个竞争资源的时候,那么就会涉及到进程对资源的加锁和释放,这样才能保证数据的安全访问.分布式锁实现的方案有很多 ...

  8. 基于数据库、redis和zookeeper实现的分布式锁

    基于数据库 基于数据库(MySQL)的方案,一般分为3类:基于表记录.乐观锁和悲观锁 基于表记录 用表主键或表字段加唯一性索引便可实现,如下: CREATE TABLE `database_lock` ...

  9. 基于Zookeeper实现的分布式互斥锁 - InterProcessMutex

    Curator是ZooKeeper的一个客户端框架,其中封装了分布式互斥锁的实现,最为常用的是InterProcessMutex,本文将对其进行代码剖析 简介 InterProcessMutex基于Z ...

随机推荐

  1. django需要了解的

    搞得差不多就去看看类和对象,看看oop是什么,多用lambda,学学md5加密. 你应当了解,django不是服务器,只提供服务.因此,学习nginx.或是apache是必要的.(IIS不了解,不过题 ...

  2. [one day one question] express 不缓存如何实现

    问题描述: express 默认缓存,这怎么破? 解决方案: apiRoutes.use(function (req, res, next) { res.setHeader('Cache-Contro ...

  3. MAC nginx代理设置

    问题: 10.154.156.83:10081私服不存在了.但是不能改.用nginx代理至maven.xx.cn 增加换回地址: sudo ifconfig lo0 add 10.154.156.83 ...

  4. KALI视频学习31-35

    (三十一)Kali漏洞利用之SET Social Enginnering Toolkit(SET)是一个开源.Python驱动的社会工程学渗透测试工具,提供了非常丰富的攻击向量库.是开源的社会工程学套 ...

  5. stm32 Flash读写独立函数[库函数]

    一. stm32的FLASH分为 1.主存储块:用于保存具体的程序代码和用户数据,主存储块是以页为单位划分的, 一页大小为1KB.范围为从地址0x08000000开始的128KB内. 2.信息块   ...

  6. jQuery Mobile中的页面加载与跳转机制

    第一次做用jQuery Mobile做东西,发现一些跟平时的思维习惯不太一样的.其中这个框架的页面加载机制便是其中一个.如果不明白其中的奥秘,往往会出现一些让人摸不着头脑的怪现象,比如页面进入后点击按 ...

  7. luogu p1101 单词方阵

    https://www.luogu.org/problem/show?pid=1101 很恶心的代码  就是八个方向都搜索 #include<bits/stdc++.h> using na ...

  8. POJ 1386 Play on Words(欧拉路)

    http://poj.org/problem?id=1386 题意: 给出多个单词,只有单词首字母与上一个单子的末尾字母相同时可以连接,判断所有字母是否可以全部连接在一起. 思路: 判断是否存在欧拉道 ...

  9. 安全之路:Web渗透技术及实战案例解析(第2版)

    安全之路:Web渗透技术及实战案例解析(第2版)

  10. Qt5_pro_02

    1.g++ 编译参数 如果 用g++编译时,命令行是这样的:“g++ main.cpp -std=c++0x -pthread” 则在Qt的pro文件中这样设置: QMAKE_CXXFLAGS += ...