canal源码之BooleanMutex(基于AQS中共享锁实现)
在看canal源码时发现一个有趣的锁实现--BooleanMutex
这个锁在canal里面多处用到,相当于一个开关,比如系统初始化/授权控制,没权限时阻塞等待,有权限时所有线程都可以快速通过
先看它的核心基于AQS的锁实现:
private final class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 2559471934544126329L;
/** State value representing that TRUE */
private static final int TRUE = 1;
/** State value representing that FALSE */
private static final int FALSE = 2;
private boolean isTrue(int state) {
return (state & TRUE) != 0;
}
/**
* 实现AQS的接口,获取共享锁的判断
*/
protected int tryAcquireShared(int state) {
// 如果为true,直接允许获取锁对象
// 如果为false,进入阻塞队列,等待被唤醒
return isTrue(getState()) ? 1 : -1;
}
/**
* 实现AQS的接口,释放共享锁的判断
*/
protected boolean tryReleaseShared(int ignore) {
// 始终返回true,代表可以release
return true;
}
boolean innerState() {
return isTrue(getState());
}
void innerGet() throws InterruptedException {
acquireSharedInterruptibly(0);
}
void innerGet(long nanosTimeout) throws InterruptedException, TimeoutException {
if (!tryAcquireSharedNanos(0, nanosTimeout)) throw new TimeoutException();
}
void innerSetTrue() {
for (;;) {
int s = getState();
if (s == TRUE) {
return; // 直接退出
}
if (compareAndSetState(s, TRUE)) {// cas更新状态,避免并发更新true操作
releaseShared(0);// 释放一下锁对象,唤醒一下阻塞的Thread
return;
}
}
}
void innerSetFalse() {
for (;;) {
int s = getState();
if (s == FALSE) {
return; // 直接退出
}
if (compareAndSetState(s, FALSE)) {// cas更新状态,避免并发更新false操作
return;
}
}
}
}
它重写了AQS中共享锁的判断可持有方法tryAcquireShared和判断可释放锁的方法tryReleaseShared
也就是说,它是重写AQS中共享锁的方法来实现的,有意思的是它不像普通AQS实现的共享锁,比如Semaphore这种有许可证个数,也就是同时能被几个线程持有是固定的,而它理论上只要打开了开关就允许任意线程通过
下面看下它是怎么实现的:
首先它定义了两个int类型属性:
/** State value representing that TRUE */
private static final int TRUE = 1;
/** State value representing that FALSE */
private static final int FALSE = 2;
这两个属性代表了AQS中state的值,也就是说这把锁中的state值始终为1或者2,看下下面这两个方法
void innerSetTrue() {
for (;;) {
int s = getState();
if (s == TRUE) {
return; // 直接退出
}
if (compareAndSetState(s, TRUE)) {// cas更新状态,避免并发更新true操作
releaseShared(0);// 释放一下锁对象,唤醒一下阻塞的Thread
return;
}
}
}
void innerSetFalse() {
for (;;) {
int s = getState();
if (s == FALSE) {
return; // 直接退出
}
if (compareAndSetState(s, FALSE)) {// cas更新状态,避免并发更新false操作
return;
}
}
}
显而易见,这两个方法都自旋的CAS改变state的值,那这两个方法在哪里调用呢?
public void set(Boolean mutex) {
if (mutex) {
sync.innerSetTrue();
} else {
sync.innerSetFalse();
}
}
这个方法封装了改变state值的方法,其实它就相当于我们常用锁的加锁和释放锁方法,原因在于它获取共享锁的判断:
protected int tryAcquireShared(int state) {
return isTrue(getState()) ? 1 : -1;
}
private boolean isTrue(int state) {
return (state & TRUE) != 0;
}
由于state值始终为1或0,当state值为0时isTrue返回false,tryAcquireShared返回-1,AQS在共享锁的获取锁判断中如果tryAcquireShared<0代表共享锁许可证已经颁发完,后续申请锁的线程需要进入FIFO队列等待
相反如果state值为1,tryAcquireShared>0就直接获取锁对象
所以,当set(false)的时候,自旋的CAS把state值改成0,线程需要等待,相反set(true)就能获取锁成功
canal源码之BooleanMutex(基于AQS中共享锁实现)的更多相关文章
- 学习JUC源码(1)——AQS同步队列(源码分析结合图文理解)
前言 最近结合书籍<Java并发编程艺术>一直在看AQS的源码,发现AQS核心就是:利用内置的FIFO双向队列结构来实现线程排队获取int变量的同步状态,以此奠定了很多并发包中大部分实现基 ...
- 【java集合框架源码剖析系列】java源码剖析之java集合中的折半插入排序算法
注:关于排序算法,博主写过[数据结构排序算法系列]数据结构八大排序算法,基本上把所有的排序算法都详细的讲解过,而之所以单独将java集合中的排序算法拿出来讲解,是因为在阿里巴巴内推面试的时候面试官问过 ...
- 源码分析系列1:HashMap源码分析(基于JDK1.8)
1.HashMap的底层实现图示 如上图所示: HashMap底层是由 数组+(链表)+(红黑树) 组成,每个存储在HashMap中的键值对都存放在一个Node节点之中,其中包含了Key-Value ...
- Java并发包源码学习系列:AQS共享式与独占式获取与释放资源的区别
目录 Java并发包源码学习系列:AQS共享模式获取与释放资源 独占式获取资源 void acquire(int arg) boolean acquireQueued(Node, int) 独占式释放 ...
- 3D语音天气球(源码分享)——在Unity中使用Android语音服务
转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! 开篇废话: 这个项目准备分四部分介绍: 一:创建可旋转的"3D球":3 ...
- Hbase源码分析:Hbase UI中Requests Per Second的具体含义
Hbase源码分析:Hbase UI中Requests Per Second的具体含义 让运维加监控,被问到Requests Per Second(见下图)的具体含义是什么?我一时竟回答不上来,虽然大 ...
- JAVA常用集合源码解析系列-ArrayList源码解析(基于JDK8)
文章系作者原创,如有转载请注明出处,如有雷同,那就雷同吧~(who care!) 一.写在前面 这是源码分析计划的第一篇,博主准备把一些常用的集合源码过一遍,比如:ArrayList.HashMap及 ...
- java基础系列之ConcurrentHashMap源码分析(基于jdk1.8)
1.前提 在阅读这篇博客之前,希望你对HashMap已经是有所理解的,否则可以参考这篇博客: jdk1.8源码分析-hashMap:另外你对java的cas操作也是有一定了解的,因为在这个类中大量使用 ...
- 第74讲:从Spark源码的角度思考Scala中的模式匹配
今天跟随王老师学习了从源码角度去分析scala中的模式匹配的功能.让我们看看源码中的这一段模式匹配: 从代码中我们可以看到,case RegisterWorker(id,workerHost,.... ...
随机推荐
- SpringBoot开发十二-账号设置
需求介绍-账号设置 账号设置里面的上传头像(文件) 首先请求必须是一个 POST 请求,其次表单的属性 enctype = "multipart/form-data" 然后就是利用 ...
- 解决vscode+python不提示numpy函数的问题
前言 使用vscode编写numpy代码时,对于numpy.array()等方法总是无法提示.查找了很多博客后,大部分都是修改配置和安装多种vscode插件,经过尝试后方法对于我来说无效.最后在调试p ...
- sqli-labs lesson 11-15
从这一关开始我们开始进入到post注入的世界了,什么是post呢?就是数据从客户端提交到服务器端,例如我们在登录过程中,输入用户名和密码,用户名和密码以表单的形式提交,提交到服务器后服务器再进行验证. ...
- 陀螺仪、加速度计与MPU6050的关系
文章目录 一.引言 二.陀螺仪 三.加速度计 四.MPU6050 一.引言 要开始做俩轮平衡小车了,所以需要补充一些关于平衡小车的知识,首先就是如何让小车保持平衡,这是要依据小车当前的三轴角度和平衡位 ...
- SQL 练习29
查询课程名称为「数学」,且分数低于 60 的学生姓名和分数 SELECT Student.Sname,Course.Cname,SC.score FROM Student,Course,SC WHER ...
- 题解 Connect
传送门 各种骗分无果,特殊性质还手残写挂了-- 首先完全图上直接输出边权 \(\times (n-2)\) 就行了,然而我脑残乘的 \(n-1\) 看数据范围肯定是状压,但是压边肯定炸了,考虑压点 因 ...
- RHEL 7 “There are no enabled repos” 的解决方法
RHEL 7 "There are no enabled repos" 的解决方法 [root@system1 Desktop]# yum install squidLoaded ...
- 转: SIFT原理解释
1.SIFT概述 SIFT的全称是Scale Invariant Feature Transform,尺度不变特征变换,由加拿大教授David G.Lowe提出的.SIFT特征对旋转.尺度缩放.亮度变 ...
- visual studio如何检查内存泄露?
Visual Studio有专门的插件叫做Visual Leak Detector (VLD)Visual Leak Detector for Visual C++ 2008/2010/2012/20 ...
- C++智能指针的原理和实现
一.智能指针起因 在C++中,动态内存的管理是由程序员自己申请和释放的,用一对运算符完成:new和delete. new:在动态内存中为对象分配一块空间并返回一个指向该对象的指针: delete:指向 ...