博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[Curator] Multi Shared Lock 的使用与分析
阅读量:6454 次
发布时间:2019-06-23

本文共 4434 字,大约阅读时间需要 14 分钟。

  hot3.png

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
locks){}
  1. 自动创建锁对象
    • InterProcessMutexes
    • 可重入分布式锁
public InterProcessMultiLock(CuratorFramework client,                             List
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
locks;}

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

5.3 构造器

public InterProcessMultiLock(List
locks){ this.locks = ImmutableList.copyOf(locks);}public InterProcessMultiLock(CuratorFramework client, List
paths){ // paths get checked in each individual InterProcessMutex, so trust them here this(makeLocks(client, paths));}
  1. 已有锁集合
    • 做了一份不可变的集合,赋值
  2. 创建一组锁
    • makeLocks方法负责创建
private static List
makeLocks(CuratorFramework client, List
paths){ ImmutableList.Builder
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
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的。 需要保障方法内部锁状态的统一。

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

转载于:https://my.oschina.net/roccn/blog/912701

你可能感兴趣的文章
JQUERY AJAX请求
查看>>
超级账本Fabric区块链用弹珠游戏Marbles 部署
查看>>
整理Java基础知识--选择与判断
查看>>
Linux查看程序端口占用情况
查看>>
jar包冲突案例分析.md
查看>>
控制圈复杂度的9种重构技术总结
查看>>
当软件项目全部能靠自己搞定了,也能接几万元的软件项目时,未必适合创业...
查看>>
数据分析--数字找朋友
查看>>
推荐好用的开源库或软件
查看>>
18年selenium3+python3+unittest自动化测试教程(下)
查看>>
Redis集群中删除/修改节点(master、slave)(实验)
查看>>
memcache数据库和redis数据库的区别(理论)
查看>>
我的友情链接
查看>>
MyBatis+Spring结合
查看>>
Office 365之SkyDrive Pro
查看>>
脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?
查看>>
无缝滚动实现原理分析【公告栏】
查看>>
Java Web 高性能开发
查看>>
redis-cli 命令总结
查看>>
CentOS 4.4双网卡绑定,实现负载均衡
查看>>