文档章节

[Curator] Multi Shared Lock 的使用与分析

秋雨霏霏
 秋雨霏霏
发布于 2017/06/01 17:05
字数 958
阅读 48
收藏 0

Multi Shared Lock

一个管理着多把锁的容器。 当这个容器的acquire()方法调用的时候,相当于申请容器内所有的锁。 如果申请失败,那么已持有的锁会被释放掉。

而调用容器的release()方法,则意味着释放容器内所有的锁。(失败时则被忽略)

1. 关键 API

org.apache.curator.framework.recipes.locks.InterProcessMultiLock

org.apache.curator.framework.recipes.locks.InterProcessLock

2. 机制说明

多把锁放入一个容器中,统一管理。

适用于一个任务需要持有多个锁才可进行的场景。

3. 用法

3.1 创建

  1. 托管已经创建好的锁对象
    • 可以是任何锁类型
public InterProcessMultiLock(List<InterProcessLock> locks){}
  1. 自动创建锁对象
    • InterProcessMutexes
    • 可重入分布式锁
public InterProcessMultiLock(CuratorFramework client,
                             List<String> paths)

4. 错误处理

在实际使用中,必须考虑链接问题。 强烈建议:添加一个ConnectionStateListener用以处理链接中断或者丢失的情况

如果遇到链接中断SUSPENDED,在恢复链接RECONNECTED之前,就不能保证是不是还持有锁了。 而如果链接丢失LOST,那就意味着不再持有锁了。

5. 源码分析

5.1 类定义

public class InterProcessMultiLock implements InterProcessLock {}

虽然也是实现了org.apache.curator.framework.recipes.locks.InterProcessLock,但是InterProcessMultiLock并不是一个实际意义上的锁。

实现这个接口,更多意义上可以当作一个委托或者代理模式。

5.2 成员变量

public class InterProcessMultiLock implements InterProcessLock
{
    private final List<InterProcessLock> locks;
}

只有一个被管理锁对象的集合

5.3 构造器

public InterProcessMultiLock(List<InterProcessLock> locks)
{
    this.locks = ImmutableList.copyOf(locks);
}

public InterProcessMultiLock(CuratorFramework client, List<String> paths)
{
    // paths get checked in each individual InterProcessMutex, so trust them here
    this(makeLocks(client, paths));
}
  1. 已有锁集合
    • 做了一份不可变的集合,赋值
  2. 创建一组锁
    • makeLocks方法负责创建
private static List<InterProcessLock> makeLocks(CuratorFramework client, List<String> paths)
{
    ImmutableList.Builder<InterProcessLock> builder = ImmutableList.builder();
    for ( String path : paths )
    {
        InterProcessLock        lock = new InterProcessMutex(client, path);
        builder.add(lock);
    }
    return builder.build();
}
  • 注意此方法是私用静态方法,也算固定套路
    • 极限情况下,静态方法的调用效率更高(省略了this检查)
  1. 对paths逐一构建InterProcessMutex对象
  2. 将锁对象加入管理的集合中

5.4 加锁

public void acquire() throws Exception
{
    acquire(-1, null);
}

public boolean acquire(long time, TimeUnit unit) throws Exception
{
    Exception                   exception = null;
    List<InterProcessLock>      acquired = Lists.newArrayList();
    boolean                     success = true;
    for ( InterProcessLock lock : locks )
    {
        try
        {
            if ( unit == null )
            {
                lock.acquire();
                acquired.add(lock);
            }
            else
            {
                if ( lock.acquire(time, unit) )
                {
                    acquired.add(lock);
                }
                else
                {
                    success = false;
                    break;
                }
            }
        }
        catch ( Exception e )
        {
            ThreadUtils.checkInterrupted(e);
            success = false;
            exception = e;
        }
    }

    if ( !success )
    {
        for ( InterProcessLock lock : reverse(acquired) )
        {
            try
            {
                lock.release();
            }
            catch ( Exception e )
            {
                ThreadUtils.checkInterrupted(e);
                // ignore
            }
        }
    }

    if ( exception != null )
    {
        throw exception;
    }
    
    return success;
}
  1. 逐一对锁对象进行加锁操作
    1. 如果加锁成功,记录状态
    2. 如果加锁失败,则中止加锁
  2. 检查状态
    1. 如果加锁过程不是全部成功
    2. 则释放已经持有的锁
      • 此过程中的异常会被忽略
  3. 如果加锁过程出现异常,也需要对已经持有的锁进行释放
  • 由于锁对象本身就可进行互斥
    • 所以此方法没有进行并发控制

5.5 释放锁

public synchronized void release() throws Exception
{
    Exception       baseException = null;

    for ( InterProcessLock lock : reverse(locks) )
    {
        try
        {
            lock.release();
        }
        catch ( Exception e )
        {
            ThreadUtils.checkInterrupted(e);
            if ( baseException == null )
            {
                baseException = e;
            }
            else
            {
                baseException = new Exception(baseException);
            }
        }
    }

    if ( baseException != null )
    {
        throw baseException;
    }
}

逐一释放的过程

  • 锁集合是先进过倒序处理的
    • 先获得的锁,后释放
    • 保障多个锁的依赖安全
  • 释放锁的过程加上了synchronized
    • 这个时候其实对于所有锁的状态是不确保统一的(有些锁可能已经被释放)
    • 一个批次的释放过程,异常需要处理

5.6 锁状态判断

public synchronized boolean isAcquiredInThisProcess()
{
    // it's subjective what the correct meaning is here - I choose to return true
    // only if all of the locks are acquired

    for ( InterProcessLock lock : locks )
    {
        if ( !lock.isAcquiredInThisProcess() )
        {
            return false;
        }
    }
    return true;
}

同样,这个方法也是加上了synchronized的。 需要保障方法内部锁状态的统一。

只有所有锁都加锁成功,才认为获得了锁。

© 著作权归作者所有

共有 人打赏支持
秋雨霏霏
粉丝 150
博文 94
码字总数 168411
作品 0
杭州
CTO(技术副总裁)
私信 提问
Apache Curator 2.7.0 发布

Apache Curator 2.7.0 发布,此版本现已提供下载,二进制包提供在 Maven 库。更新内容请看这里: Bug 修复 [CURATOR-42] - Background guaranteed delete considers NoNode to be a failed ...

oschina
2014/11/04
2.5K
0
Apache Curator 3.0.0 发布,ZooKeeper 客户端简化

Apache Curator 3.0.0 发布,该版本带来的对 ZooKeeper 的新的动态配置 APIs 的兼容,更新内容如下: 子任务 [CURATOR-160] - Support Dynamic Reconfig [CURATOR-161] - Support Watcher R...

oschina
2015/10/15
1K
3
使用Zookeeper解决微服务架构下分布式事务问题

准备工作 单机调试zookeeper集群的话,我们需要在虚拟机里虚拟出几台“微服务器“,做这一步操作之前需要在系统中预留出来8G以上磁盘空间,4G以上物理内存。 [if !supportLists]1. [endif]虚...

A尚学堂Nancy老师
09/17
0
0
分布式利器Zookeeper(三)

前言 《分布式利器Zookeeper(一)》 《分布式利器Zookeeper(二):分布式锁》 本篇博客是分布式利器Zookeeper系列的最后一篇,涉及的话题是:Zookeeper分布式锁的代码实现、zkclient的使用、...

zfz_linux_boy
07/01
0
0
Apache Curator 2.4.2 发布

Apache Curator 就是为了简化 zookeeper客户端调用而生,利用它,可以更好的使用zookeeper。 Apache Curator 2.4.2 发布了,改进内容包括: Bug [CURATOR-74] - Documentation on InterProce...

oschina
2014/04/25
1K
0

没有更多内容

加载失败,请刷新页面

加载更多

iOS补位动画、沙漏效果、移动UITableViewCell、模拟贪吃蛇、拖拽进度等源码

iOS精选源码 JHAlertView - 一款黑白配色的HUD之沙漏效果 继承UIButton的自定义按钮SPButton 用递归算法实现iOS补位动画 iOS 长按移动UITableViewCell JHLikeButton - 有趣的点赞动画 兼容X...

Android爱开源
6分钟前
0
0
08.Beetl自定义方法以及直接访问java类方法---《Beetl视频课程》

本期视频实现了发布评论时间自定义显示; 内容简介:使用了自定义方法以及直接访问java方法实现了发布时间自定义显示 一起学beetl目录:https://my.oschina.net/u/1590490?tab=newest&catal...

Gavin-King
7分钟前
0
0
上币至iamToken

https://github.com/consenlabs/token-profile 点击Fork按钮,插入到自己的github项目中 cd /Users/shijun/Desktop/blockChain/iamToken git clone https://github.com/yellmi1983/token-pro......

八戒八戒八戒
9分钟前
0
0
spark——sparkCore源码解析之RangePartitioner

HashPartitioner分区可能导致每个分区中数据量的不均匀。而RangePartitioner分区则尽量保证每个分区中数据量的均匀,将一定范围内的数映射到某一个分区内。分区与分区之间数据是有序的,但分...

freeli
9分钟前
1
0
常用的ES6语法

什么是ES6?   ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准,已经在2015年6月正式发布了。Mozilla公司将在这个标准的基础上,推出JavaScript 2.0。   ECMAScript和JavaScr...

peakedness丶
13分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部