基于zookeeper简单实现分布式锁
https://blog.csdn.net/desilting/article/details/41280869
这里利用zookeeper的EPHEMERAL_SEQUENTIAL类型节点及watcher机制,来简单实现分布式锁。
- public enum CreateMode {
- /**
- * 持久节点:节点创建后,会一直存在,不会因客户端会话失效而删除;
- */
- PERSISTENT (0, false, false),
- /**
- * 持久顺序节点:基本特性与持久节点一致,创建节点的过程中,zookeeper会在其名字后自动追加一个单调增长的数字后缀,作为新的节点名;
- */
- PERSISTENT_SEQUENTIAL (2, false, true),
- /**
- * 临时节点:客户端会话失效或连接关闭后,该节点会被自动删除,且不能再临时节点下面创建子节点,否则报如下错:org.apache.zookeeper.KeeperException$NoChildrenForEphemeralsException;
- */
- EPHEMERAL (1, true, false),
- /**
- * 临时顺序节点:基本特性与临时节点一致,创建节点的过程中,zookeeper会在其名字后自动追加一个单调增长的数字后缀,作为新的节点名;
- */
- EPHEMERAL_SEQUENTIAL (3, true, true);
- private static final Logger LOG = LoggerFactory.getLogger(CreateMode.class);
- private boolean ephemeral;
- private boolean sequential;
- private int flag;
- CreateMode(int flag, boolean ephemeral, boolean sequential) {
- this.flag = flag;
- this.ephemeral = ephemeral;
- this.sequential = sequential;
- }
- public boolean isEphemeral() {
- return ephemeral;
- }
- public boolean isSequential() {
- return sequential;
- }
- public int toFlag() {
- return flag;
- }
- static public CreateMode fromFlag(int flag) throws KeeperException {
- switch(flag) {
- case 0: return CreateMode.PERSISTENT;
- case 1: return CreateMode.EPHEMERAL;
- case 2: return CreateMode.PERSISTENT_SEQUENTIAL;
- case 3: return CreateMode.EPHEMERAL_SEQUENTIAL ;
- default:
- LOG.error("Received an invalid flag value to convert to a CreateMode");
- throw new KeeperException.BadArgumentsException();
- }
- }
- }
public enum CreateMode { /**
* 持久节点:节点创建后,会一直存在,不会因客户端会话失效而删除;
*/
PERSISTENT (0, false, false), /**
* 持久顺序节点:基本特性与持久节点一致,创建节点的过程中,zookeeper会在其名字后自动追加一个单调增长的数字后缀,作为新的节点名;
*/
PERSISTENT_SEQUENTIAL (2, false, true), /**
* 临时节点:客户端会话失效或连接关闭后,该节点会被自动删除,且不能再临时节点下面创建子节点,否则报如下错:org.apache.zookeeper.KeeperException$NoChildrenForEphemeralsException;
*/
EPHEMERAL (1, true, false), /**
* 临时顺序节点:基本特性与临时节点一致,创建节点的过程中,zookeeper会在其名字后自动追加一个单调增长的数字后缀,作为新的节点名;
*/
EPHEMERAL_SEQUENTIAL (3, true, true);
private static final Logger LOG = LoggerFactory.getLogger(CreateMode.class);
private boolean ephemeral;
private boolean sequential;
private int flag;
CreateMode(int flag, boolean ephemeral, boolean sequential) {
this.flag = flag;
this.ephemeral = ephemeral;
this.sequential = sequential;
}
public boolean isEphemeral() {
return ephemeral;
}
public boolean isSequential() {
return sequential;
}
public int toFlag() {
return flag;
}
static public CreateMode fromFlag(int flag) throws KeeperException {
switch(flag) {
case 0: return CreateMode.PERSISTENT;
case 1: return CreateMode.EPHEMERAL;
case 2: return CreateMode.PERSISTENT_SEQUENTIAL;
case 3: return CreateMode.EPHEMERAL_SEQUENTIAL ;
default:
LOG.error("Received an invalid flag value to convert to a CreateMode");
throw new KeeperException.BadArgumentsException();
}
}
}
- package zookeeper;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.apache.zookeeper.*;
- import org.apache.zookeeper.data.Stat;
- import java.util.List;
- import java.io.IOException;
- import java.util.Collections;
- import java.util.concurrent.CountDownLatch;
- public class DistributedLock implements Watcher{
- private int threadId;
- private ZooKeeper zk = null;
- private String selfPath;
- private String waitPath;
- private String LOG_PREFIX_OF_THREAD;
- private static final int SESSION_TIMEOUT = 10000;
- private static final String GROUP_PATH = "/disLocks";
- private static final String SUB_PATH = "/disLocks/sub";
- private static final String CONNECTION_STRING = "192.168.*.*:2181";
- private static final int THREAD_NUM = 10;
- //确保连接zk成功;
- private CountDownLatch connectedSemaphore = new CountDownLatch(1);
- //确保所有线程运行结束;
- private static final CountDownLatch threadSemaphore = new CountDownLatch(THREAD_NUM);
- private static final Logger LOG = LoggerFactory.getLogger(AllZooKeeperWatcher.class);
- public DistributedLock(int id) {
- this.threadId = id;
- LOG_PREFIX_OF_THREAD = "【第"+threadId+"个线程】";
- }
- public static void main(String[] args) {
- for(int i=0; i < THREAD_NUM; i++){
- final int threadId = i+1;
- new Thread(){
- @Override
- public void run() {
- try{
- DistributedLock dc = new DistributedLock(threadId);
- dc.createConnection(CONNECTION_STRING, SESSION_TIMEOUT);
- //GROUP_PATH不存在的话,由一个线程创建即可;
- synchronized (threadSemaphore){
- dc.createPath(GROUP_PATH, "该节点由线程" + threadId + "创建", true);
- }
- dc.getLock();
- } catch (Exception e){
- LOG.error("【第"+threadId+"个线程】 抛出的异常:");
- e.printStackTrace();
- }
- }
- }.start();
- }
- try {
- threadSemaphore.await();
- LOG.info("所有线程运行结束!");
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- /**
- * 获取锁
- * @return
- */
- private void getLock() throws KeeperException, InterruptedException {
- selfPath = zk.create(SUB_PATH,null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
- LOG.info(LOG_PREFIX_OF_THREAD+"创建锁路径:"+selfPath);
- if(checkMinPath()){
- getLockSuccess();
- }
- }
- /**
- * 创建节点
- * @param path 节点path
- * @param data 初始数据内容
- * @return
- */
- public boolean createPath( String path, String data, boolean needWatch) throws KeeperException, InterruptedException {
- if(zk.exists(path, needWatch)==null){
- LOG.info( LOG_PREFIX_OF_THREAD + "节点创建成功, Path: "
- + this.zk.create( path,
- data.getBytes(),
- ZooDefs.Ids.OPEN_ACL_UNSAFE,
- CreateMode.PERSISTENT )
- + ", content: " + data );
- }
- return true;
- }
- /**
- * 创建ZK连接
- * @param connectString ZK服务器地址列表
- * @param sessionTimeout Session超时时间
- */
- public void createConnection( String connectString, int sessionTimeout ) throws IOException, InterruptedException {
- zk = new ZooKeeper( connectString, sessionTimeout, this);
- connectedSemaphore.await();
- }
- /**
- * 获取锁成功
- */
- public void getLockSuccess() throws KeeperException, InterruptedException {
- if(zk.exists(this.selfPath,false) == null){
- LOG.error(LOG_PREFIX_OF_THREAD+"本节点已不在了...");
- return;
- }
- LOG.info(LOG_PREFIX_OF_THREAD + "获取锁成功,赶紧干活!");
- Thread.sleep(2000);
- LOG.info(LOG_PREFIX_OF_THREAD + "删除本节点:"+selfPath);
- zk.delete(this.selfPath, -1);
- releaseConnection();
- threadSemaphore.countDown();
- }
- /**
- * 关闭ZK连接
- */
- public void releaseConnection() {
- if ( this.zk !=null ) {
- try {
- this.zk.close();
- } catch ( InterruptedException e ) {}
- }
- LOG.info(LOG_PREFIX_OF_THREAD + "释放连接");
- }
- /**
- * 检查自己是不是最小的节点
- * @return
- */
- public boolean checkMinPath() throws KeeperException, InterruptedException {
- List<String> subNodes = zk.getChildren(GROUP_PATH, false);
- Collections.sort(subNodes);
- int index = subNodes.indexOf( selfPath.substring(GROUP_PATH.length()+1));
- switch (index){
- case -1:{
- LOG.error(LOG_PREFIX_OF_THREAD+"本节点已不在了..."+selfPath);
- return false;
- }
- case 0:{
- LOG.info(LOG_PREFIX_OF_THREAD+"子节点中,我果然是老大"+selfPath);
- return true;
- }
- default:{
- this.waitPath = GROUP_PATH +"/"+ subNodes.get(index - 1);
- LOG.info(LOG_PREFIX_OF_THREAD+"获取子节点中,排在我前面的"+waitPath);
- try{
- zk.getData(waitPath, true, new Stat());
- return false;
- }catch(KeeperException e){
- if(zk.exists(waitPath,false) == null){
- LOG.info(LOG_PREFIX_OF_THREAD+"子节点中,排在我前面的"+waitPath+"已失踪,幸福来得太突然?");
- return checkMinPath();
- }else{
- throw e;
- }
- }
- }
- }
- }
- @Override
- public void process(WatchedEvent event) {
- if(event == null){
- return;
- }
- Event.KeeperState keeperState = event.getState();
- Event.EventType eventType = event.getType();
- if ( Event.KeeperState.SyncConnected == keeperState) {
- if ( Event.EventType.None == eventType ) {
- LOG.info( LOG_PREFIX_OF_THREAD + "成功连接上ZK服务器" );
- connectedSemaphore.countDown();
- }else if (event.getType() == Event.EventType.NodeDeleted && event.getPath().equals(waitPath)) {
- LOG.info(LOG_PREFIX_OF_THREAD + "收到情报,排我前面的家伙已挂,我是不是可以出山了?");
- try {
- if(checkMinPath()){
- getLockSuccess();
- }
- } catch (KeeperException e) {
- e.printStackTrace();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }else if ( Event.KeeperState.Disconnected == keeperState ) {
- LOG.info( LOG_PREFIX_OF_THREAD + "与ZK服务器断开连接" );
- } else if ( Event.KeeperState.AuthFailed == keeperState ) {
- LOG.info( LOG_PREFIX_OF_THREAD + "权限检查失败" );
- } else if ( Event.KeeperState.Expired == keeperState ) {
- LOG.info( LOG_PREFIX_OF_THREAD + "会话失效" );
- }
- }
- }
package zookeeper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import java.util.List;
import java.io.IOException;
import java.util.Collections;
import java.util.concurrent.CountDownLatch; public class DistributedLock implements Watcher{
private int threadId;
private ZooKeeper zk = null;
private String selfPath;
private String waitPath;
private String LOG_PREFIX_OF_THREAD;
private static final int SESSION_TIMEOUT = 10000;
private static final String GROUP_PATH = "/disLocks";
private static final String SUB_PATH = "/disLocks/sub";
private static final String CONNECTION_STRING = "192.168.*.*:2181"; private static final int THREAD_NUM = 10;
//确保连接zk成功;
private CountDownLatch connectedSemaphore = new CountDownLatch(1);
//确保所有线程运行结束;
private static final CountDownLatch threadSemaphore = new CountDownLatch(THREAD_NUM);
private static final Logger LOG = LoggerFactory.getLogger(AllZooKeeperWatcher.class);
public DistributedLock(int id) {
this.threadId = id;
LOG_PREFIX_OF_THREAD = "【第"+threadId+"个线程】";
}
public static void main(String[] args) {
for(int i=0; i < THREAD_NUM; i++){
final int threadId = i+1;
new Thread(){
@Override
public void run() {
try{
DistributedLock dc = new DistributedLock(threadId);
dc.createConnection(CONNECTION_STRING, SESSION_TIMEOUT);
//GROUP_PATH不存在的话,由一个线程创建即可;
synchronized (threadSemaphore){
dc.createPath(GROUP_PATH, "该节点由线程" + threadId + "创建", true);
}
dc.getLock();
} catch (Exception e){
LOG.error("【第"+threadId+"个线程】 抛出的异常:");
e.printStackTrace();
}
}
}.start();
}
try {
threadSemaphore.await();
LOG.info("所有线程运行结束!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 获取锁
* @return
*/
private void getLock() throws KeeperException, InterruptedException {
selfPath = zk.create(SUB_PATH,null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
LOG.info(LOG_PREFIX_OF_THREAD+"创建锁路径:"+selfPath);
if(checkMinPath()){
getLockSuccess();
}
}
/**
* 创建节点
* @param path 节点path
* @param data 初始数据内容
* @return
*/
public boolean createPath( String path, String data, boolean needWatch) throws KeeperException, InterruptedException {
if(zk.exists(path, needWatch)==null){
LOG.info( LOG_PREFIX_OF_THREAD + "节点创建成功, Path: "
+ this.zk.create( path,
data.getBytes(),
ZooDefs.Ids.OPEN_ACL_UNSAFE,
CreateMode.PERSISTENT )
+ ", content: " + data );
}
return true;
}
/**
* 创建ZK连接
* @param connectString ZK服务器地址列表
* @param sessionTimeout Session超时时间
*/
public void createConnection( String connectString, int sessionTimeout ) throws IOException, InterruptedException {
zk = new ZooKeeper( connectString, sessionTimeout, this);
connectedSemaphore.await();
}
/**
* 获取锁成功
*/
public void getLockSuccess() throws KeeperException, InterruptedException {
if(zk.exists(this.selfPath,false) == null){
LOG.error(LOG_PREFIX_OF_THREAD+"本节点已不在了...");
return;
}
LOG.info(LOG_PREFIX_OF_THREAD + "获取锁成功,赶紧干活!");
Thread.sleep(2000);
LOG.info(LOG_PREFIX_OF_THREAD + "删除本节点:"+selfPath);
zk.delete(this.selfPath, -1);
releaseConnection();
threadSemaphore.countDown();
}
/**
* 关闭ZK连接
*/
public void releaseConnection() {
if ( this.zk !=null ) {
try {
this.zk.close();
} catch ( InterruptedException e ) {}
}
LOG.info(LOG_PREFIX_OF_THREAD + "释放连接");
}
/**
* 检查自己是不是最小的节点
* @return
*/
public boolean checkMinPath() throws KeeperException, InterruptedException {
List<String> subNodes = zk.getChildren(GROUP_PATH, false);
Collections.sort(subNodes);
int index = subNodes.indexOf( selfPath.substring(GROUP_PATH.length()+1));
switch (index){
case -1:{
LOG.error(LOG_PREFIX_OF_THREAD+"本节点已不在了..."+selfPath);
return false;
}
case 0:{
LOG.info(LOG_PREFIX_OF_THREAD+"子节点中,我果然是老大"+selfPath);
return true;
}
default:{
this.waitPath = GROUP_PATH +"/"+ subNodes.get(index - 1);
LOG.info(LOG_PREFIX_OF_THREAD+"获取子节点中,排在我前面的"+waitPath);
try{
zk.getData(waitPath, true, new Stat());
return false;
}catch(KeeperException e){
if(zk.exists(waitPath,false) == null){
LOG.info(LOG_PREFIX_OF_THREAD+"子节点中,排在我前面的"+waitPath+"已失踪,幸福来得太突然?");
return checkMinPath();
}else{
throw e;
}
}
} } }
@Override
public void process(WatchedEvent event) {
if(event == null){
return;
}
Event.KeeperState keeperState = event.getState();
Event.EventType eventType = event.getType();
if ( Event.KeeperState.SyncConnected == keeperState) {
if ( Event.EventType.None == eventType ) {
LOG.info( LOG_PREFIX_OF_THREAD + "成功连接上ZK服务器" );
connectedSemaphore.countDown();
}else if (event.getType() == Event.EventType.NodeDeleted && event.getPath().equals(waitPath)) {
LOG.info(LOG_PREFIX_OF_THREAD + "收到情报,排我前面的家伙已挂,我是不是可以出山了?");
try {
if(checkMinPath()){
getLockSuccess();
}
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}else if ( Event.KeeperState.Disconnected == keeperState ) {
LOG.info( LOG_PREFIX_OF_THREAD + "与ZK服务器断开连接" );
} else if ( Event.KeeperState.AuthFailed == keeperState ) {
LOG.info( LOG_PREFIX_OF_THREAD + "权限检查失败" );
} else if ( Event.KeeperState.Expired == keeperState ) {
LOG.info( LOG_PREFIX_OF_THREAD + "会话失效" );
}
}
}
log配置文件:
- # DEFAULT
- log4j.rootLogger=INFO,CONSOLE
- #
- # Log INFO level and above messages to the console
- #
- log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
- log4j.appender.CONSOLE.Threshold=INFO
- log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
- log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} - %m%n
- log4j.appender.COMMONSTAT=org.apache.log4j.DailyRollingFileAppender
- log4j.appender.COMMONSTAT.Threshold=INFO
- log4j.appender.COMMONSTAT.File=/home/zookeeper/zookeeper-test-agent/logs/test.log
- log4j.appender.COMMONSTAT.DatePattern='.'yyyy-MM-dd
- log4j.appender.COMMONSTAT.layout=org.apache.log4j.PatternLayout
- log4j.appender.COMMONSTAT.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}] - %m%n
- log4j.logger.org.displaytag=WARN
- log4j.logger.org.apache.zookeeper=ERROR
- log4j.logger.org.springframework=WARN
- log4j.logger.org.I0Itec=WARN
- log4j.logger.commonStat=INFO,COMMONSTAT
# DEFAULT
log4j.rootLogger=INFO,CONSOLE #
# Log INFO level and above messages to the console
#
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Threshold=INFO
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} - %m%n log4j.appender.COMMONSTAT=org.apache.log4j.DailyRollingFileAppender
log4j.appender.COMMONSTAT.Threshold=INFO
log4j.appender.COMMONSTAT.File=/home/zookeeper/zookeeper-test-agent/logs/test.log
log4j.appender.COMMONSTAT.DatePattern='.'yyyy-MM-dd log4j.appender.COMMONSTAT.layout=org.apache.log4j.PatternLayout
log4j.appender.COMMONSTAT.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}] - %m%n log4j.logger.org.displaytag=WARN
log4j.logger.org.apache.zookeeper=ERROR
log4j.logger.org.springframework=WARN
log4j.logger.org.I0Itec=WARN
log4j.logger.commonStat=INFO,COMMONSTAT
运行结果:
- 2014-11-19 11:34:10,894 - 【第9个线程】成功连接上ZK服务器
- 2014-11-19 11:34:10,895 - 【第8个线程】成功连接上ZK服务器
- 2014-11-19 11:34:10,894 - 【第1个线程】成功连接上ZK服务器
- 2014-11-19 11:34:10,894 - 【第7个线程】成功连接上ZK服务器
- 2014-11-19 11:34:10,894 - 【第4个线程】成功连接上ZK服务器
- 2014-11-19 11:34:10,895 - 【第5个线程】成功连接上ZK服务器
- 2014-11-19 11:34:10,896 - 【第2个线程】成功连接上ZK服务器
- 2014-11-19 11:34:10,894 - 【第10个线程】成功连接上ZK服务器
- 2014-11-19 11:34:10,894 - 【第3个线程】成功连接上ZK服务器
- 2014-11-19 11:34:10,895 - 【第6个线程】成功连接上ZK服务器
- 2014-11-19 11:34:10,910 - 【第9个线程】节点创建成功, Path: /disLocks, content: 该节点由线程9创建
- 2014-11-19 11:34:10,912 - 【第9个线程】创建锁路径:/disLocks/sub0000000000
- 2014-11-19 11:34:10,917 - 【第6个线程】创建锁路径:/disLocks/sub0000000001
- 2014-11-19 11:34:10,917 - 【第9个线程】子节点中,我果然是老大/disLocks/sub0000000000
- 2014-11-19 11:34:10,921 - 【第3个线程】创建锁路径:/disLocks/sub0000000002
- 2014-11-19 11:34:10,922 - 【第6个线程】获取子节点中,排在我前面的/disLocks/sub0000000000
- 2014-11-19 11:34:10,923 - 【第9个线程】获取锁成功,赶紧干活!
- 2014-11-19 11:34:10,924 - 【第10个线程】创建锁路径:/disLocks/sub0000000003
- 2014-11-19 11:34:10,924 - 【第3个线程】获取子节点中,排在我前面的/disLocks/sub0000000001
- 2014-11-19 11:34:10,928 - 【第10个线程】获取子节点中,排在我前面的/disLocks/sub0000000002
- 2014-11-19 11:34:10,929 - 【第1个线程】创建锁路径:/disLocks/sub0000000004
- 2014-11-19 11:34:10,932 - 【第5个线程】创建锁路径:/disLocks/sub0000000005
- 2014-11-19 11:34:10,935 - 【第1个线程】获取子节点中,排在我前面的/disLocks/sub0000000003
- 2014-11-19 11:34:10,936 - 【第2个线程】创建锁路径:/disLocks/sub0000000006
- 2014-11-19 11:34:10,936 - 【第5个线程】获取子节点中,排在我前面的/disLocks/sub0000000004
- 2014-11-19 11:34:10,940 - 【第4个线程】创建锁路径:/disLocks/sub0000000007
- 2014-11-19 11:34:10,941 - 【第2个线程】获取子节点中,排在我前面的/disLocks/sub0000000005
- 2014-11-19 11:34:10,943 - 【第8个线程】创建锁路径:/disLocks/sub0000000008
- 2014-11-19 11:34:10,944 - 【第4个线程】获取子节点中,排在我前面的/disLocks/sub0000000006
- 2014-11-19 11:34:10,945 - 【第7个线程】创建锁路径:/disLocks/sub0000000009
- 2014-11-19 11:34:10,946 - 【第8个线程】获取子节点中,排在我前面的/disLocks/sub0000000007
- 2014-11-19 11:34:10,947 - 【第7个线程】获取子节点中,排在我前面的/disLocks/sub0000000008
- 2014-11-19 11:34:12,923 - 【第9个线程】删除本节点:/disLocks/sub0000000000
- 2014-11-19 11:34:12,926 - 【第6个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
- 2014-11-19 11:34:12,928 - 【第6个线程】子节点中,我果然是老大/disLocks/sub0000000001
- 2014-11-19 11:34:12,930 - 【第9个线程】释放连接
- 2014-11-19 11:34:12,930 - 【第6个线程】获取锁成功,赶紧干活!
- 2014-11-19 11:34:14,930 - 【第6个线程】删除本节点:/disLocks/sub0000000001
- 2014-11-19 11:34:14,937 - 【第3个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
- 2014-11-19 11:34:14,941 - 【第3个线程】子节点中,我果然是老大/disLocks/sub0000000002
- 2014-11-19 11:34:14,943 - 【第6个线程】释放连接
- 2014-11-19 11:34:14,946 - 【第3个线程】获取锁成功,赶紧干活!
- 2014-11-19 11:34:16,946 - 【第3个线程】删除本节点:/disLocks/sub0000000002
- 2014-11-19 11:34:16,949 - 【第10个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
- 2014-11-19 11:34:16,951 - 【第10个线程】子节点中,我果然是老大/disLocks/sub0000000003
- 2014-11-19 11:34:16,953 - 【第3个线程】释放连接
- 2014-11-19 11:34:16,953 - 【第10个线程】获取锁成功,赶紧干活!
- 2014-11-19 11:34:18,953 - 【第10个线程】删除本节点:/disLocks/sub0000000003
- 2014-11-19 11:34:18,957 - 【第1个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
- 2014-11-19 11:34:18,960 - 【第10个线程】释放连接
- 2014-11-19 11:34:18,961 - 【第1个线程】子节点中,我果然是老大/disLocks/sub0000000004
- 2014-11-19 11:34:18,964 - 【第1个线程】获取锁成功,赶紧干活!
- 2014-11-19 11:34:20,964 - 【第1个线程】删除本节点:/disLocks/sub0000000004
- 2014-11-19 11:34:20,967 - 【第5个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
- 2014-11-19 11:34:20,969 - 【第5个线程】子节点中,我果然是老大/disLocks/sub0000000005
- 2014-11-19 11:34:20,971 - 【第1个线程】释放连接
- 2014-11-19 11:34:20,971 - 【第5个线程】获取锁成功,赶紧干活!
- 2014-11-19 11:34:22,971 - 【第5个线程】删除本节点:/disLocks/sub0000000005
- 2014-11-19 11:34:22,974 - 【第2个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
- 2014-11-19 11:34:22,978 - 【第2个线程】子节点中,我果然是老大/disLocks/sub0000000006
- 2014-11-19 11:34:22,979 - 【第5个线程】释放连接
- 2014-11-19 11:34:22,981 - 【第2个线程】获取锁成功,赶紧干活!
- 2014-11-19 11:34:24,981 - 【第2个线程】删除本节点:/disLocks/sub0000000006
- 2014-11-19 11:34:24,985 - 【第4个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
- 2014-11-19 11:34:24,989 - 【第2个线程】释放连接
- 2014-11-19 11:34:24,989 - 【第4个线程】子节点中,我果然是老大/disLocks/sub0000000007
- 2014-11-19 11:34:24,995 - 【第4个线程】获取锁成功,赶紧干活!
- 2014-11-19 11:34:26,995 - 【第4个线程】删除本节点:/disLocks/sub0000000007
- 2014-11-19 11:34:26,998 - 【第8个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
- 2014-11-19 11:34:27,000 - 【第8个线程】子节点中,我果然是老大/disLocks/sub0000000008
- 2014-11-19 11:34:27,004 - 【第8个线程】获取锁成功,赶紧干活!
- 2014-11-19 11:34:27,004 - 【第4个线程】释放连接
- 2014-11-19 11:34:29,004 - 【第8个线程】删除本节点:/disLocks/sub0000000008
- 2014-11-19 11:34:29,007 - 【第7个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
- 2014-11-19 11:34:29,009 - 【第7个线程】子节点中,我果然是老大/disLocks/sub0000000009
- 2014-11-19 11:34:29,010 - 【第8个线程】释放连接
- 2014-11-19 11:34:29,011 - 【第7个线程】获取锁成功,赶紧干活!
- 2014-11-19 11:34:31,011 - 【第7个线程】删除本节点:/disLocks/sub0000000009
- 2014-11-19 11:34:31,017 - 【第7个线程】释放连接
- 2014-11-19 11:34:31,017 - 所有线程运行结束!
2014-11-19 11:34:10,894 - 【第9个线程】成功连接上ZK服务器
2014-11-19 11:34:10,895 - 【第8个线程】成功连接上ZK服务器
2014-11-19 11:34:10,894 - 【第1个线程】成功连接上ZK服务器
2014-11-19 11:34:10,894 - 【第7个线程】成功连接上ZK服务器
2014-11-19 11:34:10,894 - 【第4个线程】成功连接上ZK服务器
2014-11-19 11:34:10,895 - 【第5个线程】成功连接上ZK服务器
2014-11-19 11:34:10,896 - 【第2个线程】成功连接上ZK服务器
2014-11-19 11:34:10,894 - 【第10个线程】成功连接上ZK服务器
2014-11-19 11:34:10,894 - 【第3个线程】成功连接上ZK服务器
2014-11-19 11:34:10,895 - 【第6个线程】成功连接上ZK服务器
2014-11-19 11:34:10,910 - 【第9个线程】节点创建成功, Path: /disLocks, content: 该节点由线程9创建
2014-11-19 11:34:10,912 - 【第9个线程】创建锁路径:/disLocks/sub0000000000
2014-11-19 11:34:10,917 - 【第6个线程】创建锁路径:/disLocks/sub0000000001
2014-11-19 11:34:10,917 - 【第9个线程】子节点中,我果然是老大/disLocks/sub0000000000
2014-11-19 11:34:10,921 - 【第3个线程】创建锁路径:/disLocks/sub0000000002
2014-11-19 11:34:10,922 - 【第6个线程】获取子节点中,排在我前面的/disLocks/sub0000000000
2014-11-19 11:34:10,923 - 【第9个线程】获取锁成功,赶紧干活!
2014-11-19 11:34:10,924 - 【第10个线程】创建锁路径:/disLocks/sub0000000003
2014-11-19 11:34:10,924 - 【第3个线程】获取子节点中,排在我前面的/disLocks/sub0000000001
2014-11-19 11:34:10,928 - 【第10个线程】获取子节点中,排在我前面的/disLocks/sub0000000002
2014-11-19 11:34:10,929 - 【第1个线程】创建锁路径:/disLocks/sub0000000004
2014-11-19 11:34:10,932 - 【第5个线程】创建锁路径:/disLocks/sub0000000005
2014-11-19 11:34:10,935 - 【第1个线程】获取子节点中,排在我前面的/disLocks/sub0000000003
2014-11-19 11:34:10,936 - 【第2个线程】创建锁路径:/disLocks/sub0000000006
2014-11-19 11:34:10,936 - 【第5个线程】获取子节点中,排在我前面的/disLocks/sub0000000004
2014-11-19 11:34:10,940 - 【第4个线程】创建锁路径:/disLocks/sub0000000007
2014-11-19 11:34:10,941 - 【第2个线程】获取子节点中,排在我前面的/disLocks/sub0000000005
2014-11-19 11:34:10,943 - 【第8个线程】创建锁路径:/disLocks/sub0000000008
2014-11-19 11:34:10,944 - 【第4个线程】获取子节点中,排在我前面的/disLocks/sub0000000006
2014-11-19 11:34:10,945 - 【第7个线程】创建锁路径:/disLocks/sub0000000009
2014-11-19 11:34:10,946 - 【第8个线程】获取子节点中,排在我前面的/disLocks/sub0000000007
2014-11-19 11:34:10,947 - 【第7个线程】获取子节点中,排在我前面的/disLocks/sub0000000008
2014-11-19 11:34:12,923 - 【第9个线程】删除本节点:/disLocks/sub0000000000
2014-11-19 11:34:12,926 - 【第6个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
2014-11-19 11:34:12,928 - 【第6个线程】子节点中,我果然是老大/disLocks/sub0000000001
2014-11-19 11:34:12,930 - 【第9个线程】释放连接
2014-11-19 11:34:12,930 - 【第6个线程】获取锁成功,赶紧干活!
2014-11-19 11:34:14,930 - 【第6个线程】删除本节点:/disLocks/sub0000000001
2014-11-19 11:34:14,937 - 【第3个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
2014-11-19 11:34:14,941 - 【第3个线程】子节点中,我果然是老大/disLocks/sub0000000002
2014-11-19 11:34:14,943 - 【第6个线程】释放连接
2014-11-19 11:34:14,946 - 【第3个线程】获取锁成功,赶紧干活!
2014-11-19 11:34:16,946 - 【第3个线程】删除本节点:/disLocks/sub0000000002
2014-11-19 11:34:16,949 - 【第10个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
2014-11-19 11:34:16,951 - 【第10个线程】子节点中,我果然是老大/disLocks/sub0000000003
2014-11-19 11:34:16,953 - 【第3个线程】释放连接
2014-11-19 11:34:16,953 - 【第10个线程】获取锁成功,赶紧干活!
2014-11-19 11:34:18,953 - 【第10个线程】删除本节点:/disLocks/sub0000000003
2014-11-19 11:34:18,957 - 【第1个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
2014-11-19 11:34:18,960 - 【第10个线程】释放连接
2014-11-19 11:34:18,961 - 【第1个线程】子节点中,我果然是老大/disLocks/sub0000000004
2014-11-19 11:34:18,964 - 【第1个线程】获取锁成功,赶紧干活!
2014-11-19 11:34:20,964 - 【第1个线程】删除本节点:/disLocks/sub0000000004
2014-11-19 11:34:20,967 - 【第5个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
2014-11-19 11:34:20,969 - 【第5个线程】子节点中,我果然是老大/disLocks/sub0000000005
2014-11-19 11:34:20,971 - 【第1个线程】释放连接
2014-11-19 11:34:20,971 - 【第5个线程】获取锁成功,赶紧干活!
2014-11-19 11:34:22,971 - 【第5个线程】删除本节点:/disLocks/sub0000000005
2014-11-19 11:34:22,974 - 【第2个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
2014-11-19 11:34:22,978 - 【第2个线程】子节点中,我果然是老大/disLocks/sub0000000006
2014-11-19 11:34:22,979 - 【第5个线程】释放连接
2014-11-19 11:34:22,981 - 【第2个线程】获取锁成功,赶紧干活!
2014-11-19 11:34:24,981 - 【第2个线程】删除本节点:/disLocks/sub0000000006
2014-11-19 11:34:24,985 - 【第4个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
2014-11-19 11:34:24,989 - 【第2个线程】释放连接
2014-11-19 11:34:24,989 - 【第4个线程】子节点中,我果然是老大/disLocks/sub0000000007
2014-11-19 11:34:24,995 - 【第4个线程】获取锁成功,赶紧干活!
2014-11-19 11:34:26,995 - 【第4个线程】删除本节点:/disLocks/sub0000000007
2014-11-19 11:34:26,998 - 【第8个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
2014-11-19 11:34:27,000 - 【第8个线程】子节点中,我果然是老大/disLocks/sub0000000008
2014-11-19 11:34:27,004 - 【第8个线程】获取锁成功,赶紧干活!
2014-11-19 11:34:27,004 - 【第4个线程】释放连接
2014-11-19 11:34:29,004 - 【第8个线程】删除本节点:/disLocks/sub0000000008
2014-11-19 11:34:29,007 - 【第7个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
2014-11-19 11:34:29,009 - 【第7个线程】子节点中,我果然是老大/disLocks/sub0000000009
2014-11-19 11:34:29,010 - 【第8个线程】释放连接
2014-11-19 11:34:29,011 - 【第7个线程】获取锁成功,赶紧干活!
2014-11-19 11:34:31,011 - 【第7个线程】删除本节点:/disLocks/sub0000000009
2014-11-19 11:34:31,017 - 【第7个线程】释放连接
2014-11-19 11:34:31,017 - 所有线程运行结束!
基于zookeeper简单实现分布式锁的更多相关文章
- 基于zookeeper实现的分布式锁
基于zookeeper实现的分布式锁 2011-01-27 • 技术 • 7 条评论 • jiacheo •14,941 阅读 A distributed lock base on zookeeper ...
- 利用ZooKeeper简单实现分布式锁
1.分布式锁的由来: 在程序开发过程中不得不考虑的就是并发问题.在java中对于同一个jvm而言,jdk已经提供了lock和同步等.但是在分布式情况下,往往存在多个进程对一些资源产生竞争关系,而这些进 ...
- 基于Zookeeper实现多进程分布式锁
一.zookeeper简介及基本操作 Zookeeper 并不是用来专门存储数据的,它的作用主要是用来维护和监控你存储的数据的状态变化.当对目录节点监控状态打开时,一旦目录节点的状态发生变化,Watc ...
- 基于zookeeper实现高性能分布式锁
实现原理:利用zookeeper的持久性节点和Watcher机制 具体步骤: 1.创建持久性节点 zkLock 2.在此父节点下创建子节点列表,name按顺序定义 3.Java程序获取该节点下的所有顺 ...
- SpringBoot基于数据库实现简单的分布式锁
本文介绍SpringBoot基于数据库实现简单的分布式锁. 1.简介 分布式锁的方式有很多种,通常方案有: 基于mysql数据库 基于redis 基于ZooKeeper 网上的实现方式有很多,本文主要 ...
- 基于 Redis 实现简单的分布式锁
摘要 分布式锁在很多应用场景下是非常有效的手段,比如当运行在多个机器上的不同进程需要访问同一个竞争资源的时候,那么就会涉及到进程对资源的加锁和释放,这样才能保证数据的安全访问.分布式锁实现的方案有很多 ...
- 基于Redis实现简单的分布式锁【理论】
摘要 分布式锁在很多应用场景下是非常有效的手段,比如当运行在多个机器上的不同进程需要访问同一个竞争资源的时候,那么就会涉及到进程对资源的加锁和释放,这样才能保证数据的安全访问.分布式锁实现的方案有很多 ...
- 基于数据库、redis和zookeeper实现的分布式锁
基于数据库 基于数据库(MySQL)的方案,一般分为3类:基于表记录.乐观锁和悲观锁 基于表记录 用表主键或表字段加唯一性索引便可实现,如下: CREATE TABLE `database_lock` ...
- 基于Zookeeper实现的分布式互斥锁 - InterProcessMutex
Curator是ZooKeeper的一个客户端框架,其中封装了分布式互斥锁的实现,最为常用的是InterProcessMutex,本文将对其进行代码剖析 简介 InterProcessMutex基于Z ...
随机推荐
- 使用nagios+python监控nginx进程数
1.编写python脚本监控nginx #!/usr/bin/python # -*- coding: utf-8 -*- import os, sys, time import string imp ...
- STM32 IO口双向问题
源: STM32 IO口双向问题
- Harbor 企业级 Docker Registry
HarBor项目:https://github.com/vmware/harbor 下载:https://github.com/vmware/harbor/releases 安装文档:https:// ...
- LCD1602小程序
1显示数据 typedef struct { unsigned long int mL_data; unsigned long int L_data; unsigned long int M3_dat ...
- apm的学习资料
百度搜索 apm博客园 实现自己的APM http://www.cnblogs.com/Kevin-moon/archive/2009/02/23/1395039.html 异步机制,一共5篇文 ...
- building '_mysql' extension error: [WinError 2] 系统找不到指定的文件。
D:\4yanjiiu\APIzidong\MySQL-python-1.2.5>py running install running bdist_egg running egg_info wr ...
- 山东省第四届ACM程序设计竞赛部分题解
A : Rescue The Princess 题意: 给你平面上的两个点A,B,求点C使得A,B,C逆时针成等边三角形. 思路: http://www.cnblogs.com/E-star/arch ...
- 使用 while 循环
与 for 循环不同,while 循环会一直运行,直到给定条件不满足为止.例如,下面的 while 循环从 x=0 开始.每次循环都会检查 x<=10 是否成立.如果成立,就执行循环内部的表达式 ...
- Visitor(访问者)
意图: 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中.TemplateMethod 使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤. 适用性: 一次性实现一个算法的不变的部分, ...
- Adapter Class/Object(适配器)
意图: 将一个类的接口转换成客户希望的另外一个接口.Adapter 模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作. 适用性: 你想使用一个已经存在的类,而它的接口不符合你的需求. 你想 ...