分布式锁之Zookeeper实现
锁接口
参照一般的Java锁都会有lock()和unlock方法。我们可以先定义一个zookeeper锁的接口:ZKLockInterface.java
package zklock;
public interface ZKLockInterface {
void zkLock();
void zkUnlock();
}
实现锁模板
ZKLockAbstractTemplate.java
package zklock;
import com.github.zkclient.ZkClient;
public abstract class ZKLockAbstractTemplate implements ZKLockInterface {
public static final String ZK_SERVER = "localhost:2181";
public static final int ZK_TIMEOUT = 30 * 1000;
public static final String ZK_LOCK_PATH ="/zklock";
ZkClient zkClient = new ZkClient(ZK_SERVER, ZK_TIMEOUT);
public void zkLock() {
if (tryZkLock()) {
System.out.println(Thread.currentThread().getName() + "获取锁");
} else {
waitZkLock();
zkLock();
}
}
public void zkUnlock() {
if (zkClient != null) {
zkClient.close();
System.out.println(Thread.currentThread().getName() + "释放锁");
}
}
protected abstract void waitZkLock();
protected abstract boolean tryZkLock();
}
Zookeeper锁实现类
ZKLock.java
package zklock;
import com.github.zkclient.IZkDataListener;
import java.util.concurrent.CountDownLatch;
public class ZKLock extends ZKLockAbstractTemplate {
private CountDownLatch countDownLatch = new CountDownLatch(1);
protected boolean tryZkLock() {
try {
zkClient.createEphemeral(ZK_LOCK_PATH);
return true;
} catch (Exception e) {
return false;
}
}
protected void waitZkLock() {
IZkDataListener iZkDataListener = new IZkDataListener() {
public void handleDataChange(String s, byte[] bytes) throws Exception {
}
public void handleDataDeleted(String s) throws Exception {
if (countDownLatch != null) {
countDownLatch.countDown();
}
}
};
zkClient.subscribeDataChanges(ZK_LOCK_PATH, iZkDataListener);
if (zkClient.exists(ZK_LOCK_PATH)) {
//如果已经存在那么进行等待
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
zkClient.unsubscribeDataChanges(ZK_LOCK_PATH, iZkDataListener);
}
}
}
模拟对一个获取订单号的方法加锁 ##:
OrderService.java
package test;
import zklock.ZKLock;
public class OrderService {
private static int orderNum = 1;
private ZKLock lock = new ZKLock();
public int getOrderNum() {
try {
lock.zkLock();
return orderNum++;
} catch (Exception e) {
return -1;
} finally {
lock.zkUnlock();
}
}
}
测试ZKLock模拟不同进程获取订单号
ZKLockTest.java
package test;
public class ZKLockTest {
public static void main(String[] args) {
for (int i = 0; i < 20; i++) {
new Thread(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName() + "获得单号" + new OrderService().getOrderNum());
}
}).start();
}
}
}