zookeeper lock自定义锁的死锁问题
OrderService
public class OrderService implements Runnable {
private OrderNumGenerator orderNumGenerator = new OrderNumGenerator();
private Lock lock = new ZookeeperDistrbuteLock();
public void run() {
getNumber();
}
public void getNumber() {
lock.getlock();
String number = orderNumGenerator.getNumber();
lock.unlock();
}
public static void main(String[] args) {
OrderService orderService = new OrderService();
System.out.println("####生成唯一订单号###");
for (int i = 0; i < 100; i++) {
new Thread(new OrderService()).start();
}
}
}
Lock
public interface Lock {
void getlock();
void unlock();
}
ZookeeperAbstractLock
public abstract class ZookeeperAbstractLock implements Lock {
private static final String CONNECTSTRING = "127.0.0.1:2181";
protected ZkClient zkClient = new ZkClient(CONNECTSTRING);
protected static final String PATH = "/lock";
@Override
public void getlock() {
if(trylock()){
}else{
waitlock();
getlock();
}
}
abstract boolean trylock();
abstract void waitlock() ;
@Override
public void unlock() {
if(zkClient!=null){
zkClient.close();
}
}
}
ZookeeperDistrbuteLock
public class ZookeeperDistrbuteLock extends ZookeeperAbstractLock {
private CountDownLatch countDownLatch =null;
@Override
boolean trylock() {
try {
zkClient.createEphemeral(PATH);
return true;
}catch (Exception e){
return false;
}
}
@Override
void waitlock() {
IZkDataListener iZkDataListener = new IZkDataListener() {
@Override
public void handleDataChange(String s, Object o) throws Exception {
}
@Override
public void handleDataDeleted(String s) throws Exception {
if(countDownLatch!=null){
countDownLatch.countDown();
}
}
};
System.out.print(Thread.currentThread().getId()+"开启了监听器!");
zkClient.subscribeDataChanges(PATH,iZkDataListener);
if(zkClient.exists(PATH)){
try {
countDownLatch = new CountDownLatch(1);
System.out.print(Thread.currentThread().getId()+"我进等待了!");
countDownLatch.await();
System.out.println(Thread.currentThread().getId()+"我等到了!");
}catch (Exception e){
e.printStackTrace();
}
}
}
}
问题1:为什么要先配置监听器? 如果后配置监听器会导致监听器未启动,线程便进入await,await等不到countDownLatch.countDown();就会一直处于等待状态,陷入死锁。 问题2: 如果按照1的描述,那么就不应该有线程能跳出await。为什么后面的代码还会执行呢?请看下图 可以跳出监听器的都是在之前一次进入的时候,所占的资源没有被占用,所以已经开启了监听器。这个线程不结束,监听器就不结束。在接下来争抢资源的过程中,监听器是已存在的,所以可以跳出await。 3.以上代码是正确的逻辑,错误的逻辑是在判断之后配置监听器。
|