ReentrantLock源码阅读
默认构造方法初始化同步器为非公平同步器
/**
* Creates an instance of {@code ReentrantLock}.
* This is equivalent to using {@code ReentrantLock(false)}.
*/
public ReentrantLock() {
sync = new NonfairSync();
}
lock()方法调用的是sync的lock()方法
public void lock() {
sync.lock();
}
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
如果将state从0改为1成功,那么将属性exclusiveOwnerThread改为当前线程,代表获得锁成功
protected final boolean compareAndSetState(int expect, int update) {
// See below for intrinsics setup to support this
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
protected final void setExclusiveOwnerThread(Thread thread) {
exclusiveOwnerThread = thread;
}
修改失败走acquire,参数arg为1
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
三步走
1.tryAcquire调用的是nonfairTryAcquire
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
//aquire为1
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
//这个逻辑什么时候会走?其他线程第一次抢锁失败,然后恰好获得锁的线程释放了锁?
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
//获得锁的线程重入会走这个逻辑
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
2.又一次抢锁失败,且不是当前线程重入,tryAcquire返回false,走下一步逻辑acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
2.1 addWaiter(Node.EXCLUSIVE) (将新节点插入尾节点之后,如果尾节点为空,初始化一个新节点,没有线程,既是头也是尾,返回新节点有thread没有addwaiter)
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
//如果有尾节点,将当前节点插入尾节点之后(可能其他线程也在做此事,失败了没关系下一步会处理)
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);
return node;
}
Node(Thread thread, Node mode) { // Used by addWaiter
this.nextWaiter = mode;
this.thread = thread;
}
private Node enq(final Node node) {
for (;;) {
Node t = tail;
//尾节点为空,初始化一个新节点,头和尾都指向他
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
//将node节点放入尾节点之后,一次次直到成功
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
Node() { // Used to establish initial head or SHARED marker
}
2.2 acquireQueued
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
//如果前一个结点是头节点,尝试获得锁,获得锁后,将自己设为头节点,前头节点置空
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
//将当前节点的前一个结点的waitStatus改为-1(循环直到成功),挂起当前节点lockSupport.park
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
ReentrantLock源码阅读的更多相关文章
- Java多线程——ReentrantLock源码阅读
上一章<AQS源码阅读>讲了AQS框架,这次讲讲它的应用类(注意不是子类实现,待会细讲). ReentrantLock,顾名思义重入锁,但什么是重入,这个锁到底是怎样的,我们来看看类的注解 ...
- Java多线程——ReentrantReadWriteLock源码阅读
之前讲了<AQS源码阅读>和<ReentrantLock源码阅读>,本次将延续阅读下ReentrantReadWriteLock,建议没看过之前两篇文章的,先大概了解下,有些内 ...
- 《java.util.concurrent 包源码阅读》13 线程池系列之ThreadPoolExecutor 第三部分
这一部分来说说线程池如何进行状态控制,即线程池的开启和关闭. 先来说说线程池的开启,这部分来看ThreadPoolExecutor构造方法: public ThreadPoolExecutor(int ...
- Java并发系列[5]----ReentrantLock源码分析
在Java5.0之前,协调对共享对象的访问可以使用的机制只有synchronized和volatile.我们知道synchronized关键字实现了内置锁,而volatile关键字保证了多线程的内存可 ...
- Rpc框架dubbo-client(v2.6.3) 源码阅读(二)
接上一篇 dubbo-server 之后,再来看一下 dubbo-client 是如何工作的. dubbo提供者服务示例, 其结构是这样的!dubbo://192.168.11.6:20880/com ...
- ThreadPoolExecutor 源码阅读
目录 ThreadPoolExecutor 源码阅读 Executor 框架 Executor ExecutorService AbstractExecutorService 构造器 状态 Worke ...
- 【详解】ThreadPoolExecutor源码阅读(二)
系列目录 [详解]ThreadPoolExecutor源码阅读(一) [详解]ThreadPoolExecutor源码阅读(二) [详解]ThreadPoolExecutor源码阅读(三) AQS在W ...
- 【详解】ThreadPoolExecutor源码阅读(一)
系列目录 [详解]ThreadPoolExecutor源码阅读(一) [详解]ThreadPoolExecutor源码阅读(二) [详解]ThreadPoolExecutor源码阅读(三) 工作原理简 ...
- 死磕 java同步系列之ReentrantLock源码解析(二)——条件锁
问题 (1)条件锁是什么? (2)条件锁适用于什么场景? (3)条件锁的await()是在其它线程signal()的时候唤醒的吗? 简介 条件锁,是指在获取锁之后发现当前业务场景自己无法处理,而需要等 ...
- CyclicBarrier源码阅读
一种允许多个线程全部等待彼此都到达某个屏障的同步机制 使用 多个线程并发执行同一个CyclicBarrier实例的await方法时,每个线程执行这个方法后,都会被暂停,只有当最后一个线程执行完awai ...
随机推荐
- React如何修改props && 子组件调用父组件方法
/** * 子组件如何更改父组件的state呢? * 父组件传递下来的props不满足要求,往往需要修改 * * * Author: shujun * Date: 2020-10-25 */ impo ...
- Net6 托管服务、FluentValidation
Net6 托管服务.FluentValidation 托管服务 1.场景,代码运行在后台.比如服务器启动的时候在后台预先加载数据到缓存,每天凌晨3点把数据导出到备份数据库,每隔5秒钟在两张表之间同步一 ...
- 老生常谈:String s1 = new String("abc") 创建了几个字符串对象及8 种基本类型的包装类和常量池
将创建 1 或 2 个字符串.如果池中已存在字符串常量"abc",则只会在堆空间创建一个字符串常量"abc".如果池中没有字符串常量"abc" ...
- QListWidget调用Clear时报错:ASSERT failure in QList<T>::at: "index out of range"的解决方法
原因:连接了信号currentRowChanged(int)和槽,当选中其中的一行时,在调用Clear函数就会报错. 解决方法:不连接currentRowChanged(int)信号和槽,改为连接it ...
- Java基础——(综合练习)选手打分
package com.zhao.test; import java.util.Scanner; public class Test17 { /* 需求 : 在唱歌比赛中,有6名评委给选手打分,分数范 ...
- leecode 19 快慢指针
记录leecode刷题思路 19. 删除链表的倒数第 N 个结点 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点. 示例 1: 输入:head = [1,2,3,4,5], n = ...
- 基于rabbitmq之MQTT协议的智能家居
智能家居项目 智能可燃气体报警器 产品是一款可燃气体报警器,如果家中燃气泄露浓度到达一定阈值,报警器检测到并上传气体浓度值给后台,后台以电话.短信.微信等方式,提醒用户家中可能有气体泄漏. 用户还可能 ...
- Flask之反向生成url
from flask import Flask, url_forapp = Flask(__name__)endpoint:用来给url起别名,通过url_for来反向生成url,如果不写则默认是函数 ...
- IDEA-mybatis逆向工程使用
首先我们需要安装mybatis逆向工程插件mybatis Generator: 然后在pom.xml文件中添加逆向工程插件: <!--mybatis逆向工程插件--> <plugin ...
- 解决mikumikudance丢失dxdx_43.dll问题
首先是MMD软件下载 我的操作系统是win10-x64 设备是19版小新pro13 mmd官网地址https://learnmmd.com/downloads/ 或者戳这里 链接:https://pa ...