1、为什么需要分布式锁
因为在集群环境中,每个类中的全局变量在每个jvm中都保存独立的一份,互不影响,不能做到保证全局唯一。所以需要分布式锁;而zookeeper中临时节点的名称唯一性以及会话保持一致性还有节点事件通知的特性决定了zookeeper可以很好的实现分布式锁;
2、代码实现
public abstract class ZookeeperAbstractLock implements ExtLock {// 集群连接地址protected String CONNECTION = "127.0.0.1:2181";// zk客户端连接protected ZkClient zkClient = new ZkClient(CONNECTION);// path路径protected String lockPath = "/path";protected CountDownLatch countDownLatch = new CountDownLatch(1);public void getLock() {if (tryLock()) {System.out.println("####获取锁成功######");} else {waitLock();getLock();}}// 获取锁abstract boolean tryLock();// 等待锁abstract void waitLock();public void unLock() {if (zkClient != null) {System.out.println("#######释放锁#########");zkClient.close();}}
public class ZookeeperDistrbuteLock extends ZookeeperAbstractLock {@Overrideboolean tryLock() {try {zkClient.createEphemeral(lockPath);return true;} catch (Exception e) {return false;}}@Overridevoid waitLock() {// 使用zk临时事件监听IZkDataListener iZkDataListener = new IZkDataListener() {public void handleDataDeleted(String path) throws Exception {if (countDownLatch != null) {countDownLatch.countDown();}}public void handleDataChange(String arg0, Object arg1) throws Exception {}};// 注册事件通知zkClient.subscribeDataChanges(lockPath, iZkDataListener);if (zkClient.exists(lockPath)) {countDownLatch = new CountDownLatch(1);try {countDownLatch.await();} catch (Exception e) {// TODO: handle exception}}// 监听完毕后,移除事件通知zkClient.unsubscribeDataChanges(lockPath, iZkDataListener);}}
public class OrderService implements Runnable {
private OrderNumGenerator orderNumGenerator = new OrderNumGenerator();
private ExtLock extLock = new ZookeeperDistrbuteLock();
public void run() {
getNumber();
}
public void getNumber() {
try {
extLock.getLock();
String number = orderNumGenerator.getNumber();
System.out.println("线程:" + Thread.currentThread().getName() + ",生成订单id:" + number);
} catch (Exception e) {
} finally {
extLock.unLock();
}
}
public static void main(String[] args) {
System.out.println("多线程生成number");
// OrderService orderService = new OrderService();
for (int i = 0; i < 100; i++) {
new Thread(new OrderService()).start();
}
}
}



