public class zkDemo implements Watcher {
private static final Logger LOG;
static {
//Keep these two lines together to keep the initialization order explicit
LOG = LoggerFactory.getLogger(ZooKeeper.class);
}
private static final CountDownLatch cdl = new CountDownLatch(1);
// static ZooKeeper zk;
static final List<String> recode = new ArrayList<String>();
boolean flag = true;
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
static Object ob = new Object();
public static void main(String[] args) throws IOException {
ExecutorService es = Executors.newFixedThreadPool( 10 );
List<Future<String>> li = new ArrayList<Future<String>>();
for (int i=0;i<10;i++){
final String num = i +"";
Future<String> fv = es.submit( new Callable<String>() {
@Override
public String call() throws IOException, KeeperException, InterruptedException {
ZooKeeper zk = new ZooKeeper("192.168.0.170:2181", 5000, new zkDemo());
String path = zk.create("/lock/test-", "456".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
String small_path = get_smaller_node(path);
if (small_path == null){
System.out.println( num+"由于不是第一次注册,立马获取了锁");
}else{
//先不注册wather判断存不存在
if(zk.exists( small_path, false ) == null){
System.out.println( num+"获取了锁,path为:"+ path+"。第一次判断");
synchronized (recode){
recode.add( num );
}
//等待所有的都注册好之后再退出 然后关闭session
while(recode.size() < 10){
//这个是多线程的interupt
Thread.yield();
}
System.out.println( recode );
}else{
boolean flag = true;
zkDemo de = new zkDemo();
//注册一个watcher,当de的全局变量变成false的时候说明上一个节点被删除了
System.out.println( num+"开始判断先前一个节点"+small_path+"是否存在" );
//实验证明当一个节点删除之后,de的全局变量不变
System.out.println( de );
Stat st = zk.exists( small_path, de );
synchronized (recode){
recode.add( num );
}
boolean flag_result = true;
while (flag_result) {
flag_result = de.isFlag();
Thread.yield();
}
//这个方式不好的是万一一开始上一个节点删除之前 本节点还没注册好watcher就炸了
System.out.println( num+"获取了锁,path为:"+ path+"。watcher被动获取");
/**
* start do your job
*/
/**
* end your job
*/
}
}
zk.close();
return num;
}
private String get_smaller_node(String path){
int num = Integer.parseInt(path.split( "-" )[1])-1;
if (num < 0){
return null;
}else{
String a = num +"";
String result = "/lock/test-";
for(int i =0;i<10-a.length();i++){
result = result+"0";
}
result = result + a;
return result;
}
}
} );
li.add( fv );
}
for (Future<String> fv : li){
try {
System.out.println(fv.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
es.shutdown();
}
//监听到事件时进行处理
public void process(WatchedEvent event) {
// LOG.info( "事件的路径为:" +event.getPath() );
// if (Watcher.Event.KeeperState.SyncConnected == event.getState()) {
// cdl.countDown();
// }
// if (event.getType() == Event.EventType.NodeCreated) {
// System.out.println( event.getPath() + "创建了");
// }
// if (event.getType() == Event.EventType.NodeDataChanged) {
// System.out.println( event.getPath() + "数据改变了");
// System.out.println( event.getState());
// }
if (event.getType() == Event.EventType.NodeDeleted){
System.out.println( "节点被删除:"+event.getPath() );
System.out.println( this );
this.setFlag(false);
}
}
}
打印结果:
2开始判断先前一个节点/lock/test-0000000287是否存在
zkDemo@54c96913
4开始判断先前一个节点/lock/test-0000000286是否存在
zkDemo@350bad47
8开始判断先前一个节点/lock/test-0000000283是否存在
zkDemo@5585bfef
0开始判断先前一个节点/lock/test-0000000285是否存在
zkDemo@4462917e
5开始判断先前一个节点/lock/test-0000000284是否存在
zkDemo@60e57dfb
1开始判断先前一个节点/lock/test-0000000282是否存在
zkDemo@4221aac4
3开始判断先前一个节点/lock/test-0000000288是否存在
zkDemo@7d2b165d
7开始判断先前一个节点/lock/test-0000000280是否存在
zkDemo@11964ed6
9开始判断先前一个节点/lock/test-0000000281是否存在
zkDemo@3cac98cf
6获取了锁,path为:/lock/test-0000000280。第一次判断
[4, 0, 8, 3, 7, 5, 1, 2, 9, 6]
节点被删除:/lock/test-0000000280
zkDemo@11964ed6
7获取了锁,path为:/lock/test-0000000281。watcher被动获取
节点被删除:/lock/test-0000000281
zkDemo@3cac98cf
9获取了锁,path为:/lock/test-0000000282。watcher被动获取
节点被删除:/lock/test-0000000282
zkDemo@4221aac4
1获取了锁,path为:/lock/test-0000000283。watcher被动获取
节点被删除:/lock/test-0000000283
zkDemo@5585bfef
8获取了锁,path为:/lock/test-0000000284。watcher被动获取
节点被删除:/lock/test-0000000284
zkDemo@60e57dfb
5获取了锁,path为:/lock/test-0000000285。watcher被动获取
节点被删除:/lock/test-0000000285
zkDemo@4462917e
0获取了锁,path为:/lock/test-0000000286。watcher被动获取
节点被删除:/lock/test-0000000286
zkDemo@350bad47
0
1
4获取了锁,path为:/lock/test-0000000287。watcher被动获取
节点被删除:/lock/test-0000000287
zkDemo@54c96913
2获取了锁,path为:/lock/test-0000000288。watcher被动获取
节点被删除:/lock/test-0000000288
zkDemo@7d2b165d
3获取了锁,path为:/lock/test-0000000289。watcher被动获取
2
3
4
5
6
7
8
9
说明:本例用线程池模拟了分布式锁的使用
遇到的问题:
1.获取本节点上一个节点的计算方式(zk临时自增节点的path规范)
2.多线程while循环导致其他线程卡死。可以用 Thread.yield();将当前的线程锁交出(可能成功也可能失败)。