排它锁(Exclusive Locks,简称X锁)又称之为独占锁,是一种基本的锁类型。排他锁的核心就是如何保证仅有一个线程获取到锁,并且在锁释放后,可以及时地通知到其他等待获取锁定的线程。下面使用ZK实现了一个简单的排它锁。
定义锁
在ZK下定义一个临时节点节点表示锁
/**排它锁节点**/
private final String EXCLUSIVE_LOCK = "/zk-demo/lock";
获取锁
在需要获取锁时,所有客户端都需要视图通过调用create()方法在ZK上创建这个临时节点。zk保证所有客户端中仅有一个客户端可以创建成功,如果创建成功的客户端则认为他获取了锁。同时没有获取到则需要向这个节点注册一个监听器,监听其他客户端释放锁。
释放锁
我们定义的锁是一个临时节点,有两种情况可以释放锁。
- 当前客户端发生宕机,也就是session断开则这个临时节点被移除。
- 正常业务逻辑执行完成后主动删除自己创建的临时节点。
无论在什么情况下移除了lock这个临时节点,ZK都会通知所有在/zk-demo节点上注册的子节点变更监听器。在客户端接收到通知时可以再次发起获取分布式锁的尝试
/** * 分布式锁服务接口,该接口定义了如下功能 * <ul> * <li> tryLock 一直等待锁</li> * <li> tryLock 等待一段时间,如果超时则会调用回调方法expire()</li> * </ul> * * @author zhangwei_david * @version $Id: DistributedLockService.java, v 0.1 2015年7月1日 下午9:03:33 zhangwei_david Exp $ */ public interface DistributedLockService { /** * 试图获取分布式锁,如果返回true则表示获取了锁 * * @param callback 回调接口 */ public void tryLock(CallBack callback); /** * 视图获取分布式锁,如果在指定timeout时间后容然未能够获取到锁则返回 * * @param callback * @param timeout */ public void tryLock(CallBack callback, long timeout); /** * 回调处理接口 * * @author zhangwei_david * @version $Id: DistributedLockService.java, v 0.1 2015年7月2日 上午10:59:22 zhangwei_david Exp $ */ public interface CallBack { /** * 获取分布式锁后回调方法 */ public void locked(); /** * 获取分布式锁超时回调方法 */ public void expire(); } }
/** * 分布式锁服务实现类 * @author zhangwei_david * @version $Id: DistributedLockServiceImpl.java, v 0.1 2015年7月1日 下午9:05:48 zhangwei_david Exp $ */ @Component public class DistributedLockServiceImpl implements DistributedLockService { private static final String ROOT = "/zk-demo"; /**锁的临时节点**/ private static final String LOCK = "lock"; /**排它锁节点**/ private static final String EXCLUSIVE_LOCK = ROOT + "/" + LOCK; private int sessionTimeout = 3000; /** * @see com.david.common.distributedLock.DistributedLockService#tryLock(com.david.common.distributedLock.DistributedLockService.CallBack, long) */ public void tryLock(final CallBack callback, long timeout) { try { final long expireTime = timeout > 0 ? System.currentTimeMillis() + timeout : -1; final ZooKeeper zk = getZooKeeper(); //向根节点注册一个子节点变化监听器 List<String> nodes = zk.getChildren(ROOT, new Watcher() { public void process(WatchedEvent event) { // 排它锁已经被释放,则视图获取锁 if (event.getState() == KeeperState.SyncConnected && event.getType() == EventType.NodeChildrenChanged) { doLock(zk, callback, expireTime); } } }); // 没有人获取锁则视图获取锁 if (!nodes.contains(LOCK)) { doLock(zk, callback, expireTime); } } catch (Exception e) { } } /** * * @see com.david.common.distributedLock.DistributedLockService#tryLock(com.david.common.distributedLock.DistributedLockService.CallBack) */ public void tryLock(final CallBack callback) { tryLock(callback, -1); } /** * 具体执行分布式锁,如果拥有分布式锁则执行callback回调,然后释放锁 * * @param zk * @param callback * @param expireTime 过期时间 */ private void doLock(ZooKeeper zk, CallBack callback, long expireTime) { try { if (expireTime > 0 && System.currentTimeMillis() > expireTime) { callback.expire(); return; } String path = zk .create(EXCLUSIVE_LOCK, null, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL); System.out.println(path); if (path != null) { callback.locked(); zk.delete(EXCLUSIVE_LOCK, -1); } } catch (Exception e) { } finally { try { zk.close(); } catch (InterruptedException e) { } } } /** * 获取ZooKeeper * * @param sessionTimeout * @return * @throws Exception */ private ZooKeeper getZooKeeper() throws Exception { final CountDownLatch latch = new CountDownLatch(1); ZooKeeper zk = new ZooKeeper("localhost:2181", sessionTimeout, new Watcher() { public void process(WatchedEvent event) { if (KeeperState.SyncConnected == event.getState()) { //如果客户端已经建立连接闭锁减一 latch.countDown(); } } }); // 等待连接建立 latch.await(); return zk; } /** * Getter method for property <tt>sessionTimeout</tt>. * * @return property value of sessionTimeout */ public int getSessionTimeout() { return sessionTimeout; } /** * Setter method for property <tt>sessionTimeout</tt>. * * @param sessionTimeout value to be assigned to property sessionTimeout */ public void setSessionTimeout(int sessionTimeout) { this.sessionTimeout = sessionTimeout; } }
相关推荐
zookeeper通过使用curator实现分布式锁来保证数据的一致性。 zookeeper通过使用curator实现分布式锁来保证数据的一致性。
1.zk简介 2.zk实现分布式锁
里面包含zk的分布式锁,包括原生客户端API的方式,以及框架的方式。还有red is的原生客户端API方式,以及框架的方式
12.1.9 zk的分布式锁
zk分布式锁1
zk_lock 用zk实现的分布式锁 实现分布式锁 保留线程中断特性 保留条件锁特性 同一进程内多线程竞争,进行本地排队 支持本地排队优先执行策略
java面试题Redis分布式锁+zk 分布式锁.md
此Demo采用zookeeper实现分布式锁,相比于redis实现分布式锁更加可靠
zk实现分布式锁 今天我们介绍通过redis实现分布式锁。实际上这三种和java对比看属于一类。都是属于程序外部锁。 原理剖析 上述三种分布式锁都是通过各自为依据对各个请求进行上锁,解锁从而控制放行还是拒绝。...
https://mp.csdn.net/console/uploadResources?spm=1011.2124.3001.4171
zk只会对已经创建分布式锁的系统进行创建监听,所以性能消耗很小 2、运行出现错误 redis创建锁的节点如果挂了,那就只能等待超时才能释放锁 zk因为是创建临时的lockNode,所以挂了就释放了 3、操作 redis使用起来...
利用zookeeper的临时顺序节点实现分布式锁,同时控制多个quartz示例协作执行的代码。
DB对于系统来说本身就默认为高可用组件,针对一些低频的业务使用DB实现分布式锁也是一个不错的解决方案,比如控制多机器下定时任务的起调,针对审批回调处理等,本文将给出DB实现分布式锁的一些场景以及解决方案,...
基于zookeeper实现的分布式读写锁,用Zkclient客户端实现
当前的PPT总共56页,从锁的介绍,到java锁(lock、synchronor、aqs)到分布式锁 redis、zk、数据库的悲观锁和乐观锁都有涉及,算是比较完整的一个PPT,适合涉及到锁相关的专题讲座,以及自学的PPT,后面有机会会开...
主要介绍了java使用zookeeper实现的分布式锁示例,需要的朋友可以参考下
接下来我们一起来看看,多客户端获取及释放zk分布式锁的整个流程及背后的原理。 首先大家看看下面的图,如果现在有两个客户端一起要争抢zk上的一把分布式锁,会是个什么场景? 如果大家对zk还不太了解,建议先百度...
redis和zk两种不同方式实现分布式锁,互联网开发小伙伴必备技能!
从PAXOS到ZK分布式一致性原理与实践 从PAXOS到ZK分布式一致性原理与实践