Zookeeper同步锁

最近在弄分布式

用到的是Zookeeper还只是初步用到了一下同步锁没做进一步的应用

想了解Zookeeper 大家都推荐:http://www.ibm.com/developerworks/cn/opensource/os-cn-zookeeper/这个文章 是不错


直接贴代码:

package com.zookeeper.test;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;

public class ZkDistributedLock implements Watcher {
	private ZooKeeper zk;
	private String config = "192.168.1.213:2181";
	private String root = "/locks"; // 锁的根节点
	private String lockName; // 竞争节点前缀
	private String waitNode; // 被监听的前一个节点
	private String newNode; // 当前节点
	private CountDownLatch latch; // 计数器
	private int sessionTimeout = 60 * 1000; // zookeeper会话超时时间

	/**
	 * 创建Zookeeper连接并建立跟目录
	 */
	public ZkDistributedLock(String lockName) {
		this.lockName = lockName;
		try {
			zk = new ZooKeeper(config, sessionTimeout, this);
			Stat stat = zk.exists(root, false);
			if (stat == null) {
				// 创建根节点
				zk.create(root, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE,
						CreateMode.PERSISTENT);
			}
		} catch (IOException e) {
			System.out.println("ZkDistributedLock对象初始化失败,IOException:" + e);
		} catch (KeeperException e) {
			System.out.println("ZkDistributedLock对象初始化失败,KeeperException:" + e);
		} catch (InterruptedException e) {
			System.out.println("ZkDistributedLock对象初始化失败,InterruptedException:"
					+ e);
		}
	}

	/**
	 * 监听器动作
	 */
	public void process(WatchedEvent event) {
		if (this.latch != null) {
			System.out.println("process监听被触发:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+Thread.currentThread().getId());
			this.latch.countDown();
		}
	}

	/**
	 * 上锁操作
	 * 
	 * @return
	 */
	public boolean lock() {
		if (tryLock()) {
			return true;
		} else {
			return waitForLock(waitNode, sessionTimeout);
		}
	}

	/**
	 * 尝试获取锁操作
	 * 
	 * @return
	 */
	private boolean tryLock() {
		String splitStr = "_lock_";
		try {
			// 创建临时子节点
			newNode = zk.create(root + "/" + lockName + splitStr, new byte[0],
					ZooDefs.Ids.OPEN_ACL_UNSAFE,
					CreateMode.EPHEMERAL_SEQUENTIAL);
			System.out.println("子节点:" + newNode + "成功建立!");
			// 取出所有子节点
			List<String> subNodes = zk.getChildren(root, false);
			// 取出所有lockName的锁
			List<String> lockObjNodes = new ArrayList<String>();
			for (String node : subNodes) {
				String _node = node.split(splitStr)[0];
				if (_node.equals(lockName)) {
					lockObjNodes.add(node);
				}
			}
			Collections.sort(lockObjNodes);
			if (newNode.equals(root + "/" + lockObjNodes.get(0))) {
				// 如果是最小的节点,则表示取得锁
				System.out.println("Thread" + Thread.currentThread().getId()
						+ newNode + " get lock !");
				return true;
			}
			// 如果不是最小的节点,找到比自己小1的节点
			String subNewNode = newNode.substring(newNode.lastIndexOf("/") + 1);
			waitNode = lockObjNodes.get(Collections.binarySearch(lockObjNodes,
					subNewNode) - 1);
		} catch (KeeperException e) {
			System.out.println("尝试获取锁操作失败,KeeperException:" + e);
		} catch (InterruptedException e) {
			System.out.println("尝试获取锁操作失败,InterruptedException:" + e);
		}
		return false;
	}

	/**
	 * 等待前一个节点开锁
	 * 
	 * @param lower
	 * @param waitTime
	 * @return
	 */
	private boolean waitForLock(String lower, long waitTime) {
		Stat stat;
		try {
			stat = zk.exists(root + "/" + lower, true);
			// 判断比自己小一个数的节点是否存在,如果不存在则无需等待锁,同时注册监听
			if (stat != null) {
				System.out.println("Thread " + Thread.currentThread().getId()
						+ " waiting for " + root + "/" + lower);
				this.latch = new CountDownLatch(1);
				this.latch.await(waitTime, TimeUnit.MILLISECONDS);
				System.out.println(newNode+"节点获得锁!");
				this.latch = null;
			}
			return true;
		} catch (KeeperException e) {
			System.out.println("等待前一个节点开锁失败,KeeperException:" + e);
		} catch (InterruptedException e) {
			System.out.println("等待前一个节点开锁失败,InterruptedException:" + e);
		}
		return false;
	}

	/**
	 * 解锁
	 */
	public void unlock() {
		try {
			System.out.println("子节点:" + newNode + "已解锁!");
			zk.delete(newNode, -1);
			newNode = null;
			zk.close();
		} catch (InterruptedException e) {
			System.out.println("解锁异常,InterruptedException:" + e);
		} catch (KeeperException e) {
			System.out.println("解锁异常,KeeperException:" + e);
		}
	}
}

还只是初步运用 有什么问题 欢迎指正

感觉要注意的是 会话超时 下一个锁就会自动启动 因为这情况 我在测试的时候还以为代码bug

然后还一个创建zk连接的时候

就算服务器关闭也不会报错

所以我推测创建zk连接其实只是保存了连接信息没实际访问服务器

要到访问文件目录的时候才实际连服务器

我没时间看源码

不知道这个推测是不是正确

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值