ReentrantLock源码学习总结 (二)
ReentrantLock 示例
private ReentrantLock lock = new ReentrantLock(true);
public void f(){
try {
lock.lock();
//do something
}
finally {
lock.unlock();
}
}
源码解析(公平锁-unlock流程)
ReentrantLock#unlock()
public void unlock() {
sync.release(1);
}
AbstractQueuedSynchronizer#release(int arg)
public final boolean release(int arg) {
//尝试释放锁,只有当 state == 0 才会释放成功
if (tryRelease(arg)) {
//释放成功之后,查看head节点,如果head节点不为 null,并且,head节点不为0 (可能为 -1)
Node h = head;
if (h != null && h.waitStatus != 0)
//unpark 线程
unparkSuccessor(h);
return true;
}
return false;
}
ReentrantLock.Sync#tryRelease(int arg)
protected final boolean tryRelease(int releases) {
//state - releases,上锁之后,state > 0,所以释放锁要减掉
int c = getState() - releases;
//如果当前线程并不是持有锁的线程,不能乱释放锁,直接给你抛个异常
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
//释放标志
boolean free = false;
//由于是可重入锁,所以当 c == 0 的情况下才真正释放完成
if (c == 0) {
free = true;
//设置当前线程为空
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
AbstractQueuedSynchronizer#unparkSuccessor(Node node)
private void unparkSuccessor(Node node) {
//获取head node节点的 waitStatus , < 0(-1) 就CAS 改回 0
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
//找到下一个节点
Node s = node.next;
//如果下一个节点为null,或者 已经取消抢锁了,继续往下找
if (s == null || s.waitStatus > 0) {
s = null;
//从尾部向前遍历,如果 waitStatus<=0 就赋值给 s,这样保证最前边的一个waitStatus<=0的线程可以唤醒。
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
//如果下一个节点不为 null,直接 unpark 线程,对应代码就是AbstractQueuedSynchronizer#acquireQueued(Node node, int arg) 中 的for(;;),这样线程唤醒之后,就会尝试再去获取锁了。
if (s != null)
LockSupport.unpark(s.thread);
}
总结
释放锁的流程比较简单,就是讲 state减去1,然后去队列里面找下一个节点,最后执行 unpark 方法唤醒线程。
ReentrantLock源码学习总结 (二)的更多相关文章
- 死磕 java同步系列之ReentrantLock源码解析(二)——条件锁
问题 (1)条件锁是什么? (2)条件锁适用于什么场景? (3)条件锁的await()是在其它线程signal()的时候唤醒的吗? 简介 条件锁,是指在获取锁之后发现当前业务场景自己无法处理,而需要等 ...
- Java并发之ReentrantLock源码解析(二)
在了解如何加锁时候,我们再来了解如何解锁.可重入互斥锁ReentrantLock的解锁方法unlock()并不区分是公平锁还是非公平锁,Sync类并没有实现release(int arg)方法,这里会 ...
- java源码学习(二)Integer
Integer类包含了一个原始基本类型int.Integer属性中就一个属性,它的类型就是int. 此外,这个类还提供了几个把int转成String和把String转成int的方法,同样也提供了其它跟 ...
- ReentrantLock源码学习总结 (一)
[^ ]: 以下源码分析基于JDK1.8 ReentrantLock 示例 private ReentrantLock lock = new ReentrantLock(true); public v ...
- Java集合源码学习(二)ArrayList分析
>>关于ArrayList ArrayList直接继承AbstractList,实现了List. RandomAccess.Cloneable.Serializable接口,为什么叫&qu ...
- Spring源码学习(二)AOP
----ProxyFactoryBean这个类,这是AOP使用的入口---- AOP有些特有的概念,如:advisor.advice和pointcut等等,使用或配置起来有点绕,让人感觉有些距离感,其 ...
- Java集合源码学习(二)ArrayList
1.关于ArrayList ArrayList直接继承AbstractList,实现了List. RandomAccess.Cloneable.Serializable接口,为什么叫"Arr ...
- jQuery源码学习笔记二
//添加实例属性和方法 jQuery.fn = jQuery.prototype = { // 版本,使用方式:$().jquery弹出当前引入的jquery的版本 jquery: core_vers ...
- Guava源码学习(二)Ordering
基于版本:Guava 22.0 Wiki:Ordering 0. Ordering简介 Guava的Ordering提供了链式风格的比较器的实现,我们可以用Ordering轻松构建复杂的比较器. 1. ...
随机推荐
- 【转载】C#中遍历DataTable中的数据行
在C#中的Datatable数据变量的操作过程中,有时候我们需要遍历DataTable变量获取每一行的数据值,例如将DataTable变量转换为List集合的时候,我们就会遍历DataTable变量, ...
- Beego 学习笔记13:Api编写
Api编写 1> api常用的数据的格式有json和xml这两种. 2> 下面开始讲解不同的数据格式使用的方式 1->JSON 数据直接输出. 调用 ServeJSO ...
- 85.webpack的安装失败至成功
webpack怎么安装 1.安装node.js; 2.安装webpack: npm install webpack --save-dev : 注意:webpack 4x以上,webpack将命 ...
- 你的MES今天升级了吗?
你以为把MES装上了就完事了吗?NO NO NO!乔布斯先生曾讲过“你如果出色地完成了某件事,那你应该再做一些其他的精彩事儿.不要在前一件事上徘徊太久,想想接下来该做什么.” 目前大部分企业都已经完成 ...
- ISO模型学习
PDU:协议数据单元是指层次之间传递的数据单位 物理层PDU :PDU是数据位 bit数据链路层的PDU是数据帧frame网络层的PUD是数据包 packet传输层的PDU是数据段 segment其他 ...
- 【MySQL】查看建表语句
命令如下: SHOW CREATE TABLE tbl_name 例子: mysql> show create table m_zhbess_vehicle_report\G ********* ...
- java项目路径总结,java.io.File支持的路放方式
1.直接输入路径 已maven项目为例,直接输入路径的4种方式,即是File类支持的方式: /** * FileOutpurStream以字节数组方式写入文件 * @throws IOExceptio ...
- FFMPEG 命令行工具-ffprobe
ffprobe 简介 ffprobe 是一个多媒体流分析工具.它从多媒体流中收集信息,并且以人类和机器可读的形式打印出来. 它可以用来检测多媒体流的容器类型,以及每一个多媒体流的格式和类型.它可以作为 ...
- C#实体类与XML相互转换
1.实体类与XML相互转换 将实体类转换成XML需要使用XmlSerializer类的Serialize方法,将实体类序列化. 把XML转换成相应的实体类,需要使用到XmlSerializer类的De ...
- httprunner学习12-hook 机制实现setup和teardown
前言 unittest框架里面有个非常好的概念:前置( setUp )和后置( tearDown )处理器,真正会用的人不多. HttpRunner 实际上也是从用的unittest框架,里面也有前置 ...