ReentrantReadWriteLock源码分析
代码在后面
读锁 = 共享锁
读锁写锁,公用一个Sync AQS state。
写锁是排他的,看到有人获取锁,他不会去获取,他获取了锁,别人也不会进来获取锁。
写锁的获取跟ReentarntLock一样,每次加1,是一个独占锁,只要有人获取了锁,自己就去排队,排队时候节点是EXCLUSIVE的节点,入队方法acquireQueued和ReentarntLock一样,会设置OwnerThread。
读锁先获取锁,后面有读锁进来,多个读线程共存时候,第一个读线程设置firstReader,其余读线程设置threadLocals属性,然后获取锁,读锁每次增加65536,
写锁再进来,就去排队。
读锁再又进来,读锁还是去排队,
读锁不会设置OwnerThread,只是会state增加65536,写锁会忽略大于65536的部分。
state!=0,state去掉前16位=0,说明有读锁进去,写锁不进去。
State高位存储读锁获取次数,低位存储写锁获取次数。
设置threadLocals属性的读线程unlock时候清除threadLocalMap的标记,设置firstReader的读线程unlock时候设置firstReader=null,并且state减65536,
//读锁进来,首先判断state后16位,有写锁就去排队,没有写锁就设置firstReader或者firstReaderHoldCount++或者当前线程的threadLocals并且state增加65536
//写锁进来时候,首先判断state,有读锁写锁就去排队,
1.读锁进来,不看owenerThread,看的是state,去掉前面16位=0,说明没有写线程获取锁,就设置firstReader或者threadLocalMap,state增加65536。state去掉前面16位!=0说明有写线程获得了锁,就去排队。如果队列第一个是写线程,就去排队。 如果后面还有读线程进来,照样。
2.写锁进来,state!=0,state去掉前面16位=0,说明state已经加了几个65536了,说明有线程在读,写锁要去排队。state=0说明没有写线程获取锁,没有读线程在读,就去获取锁。state!=0,state去掉前面16位!=0,说明state有写线程获取锁,就去排队。
读锁每次加65536,不设置owenerThread。写锁每次加1,设置owenerThread。
读:去掉前面16!=0就去排队,队列空设置firstReader或者threadLocalMap,第一个节点是写线程排队,第一个节点是读线程设置firstReader或者threadLocalMap。
写:state!=0,去掉前面16位=0去排队,state=0获取锁。
if (exclusiveCount(c) != 0 /*去掉前面16位,*/ && getExclusiveOwnerThread() != current)
获取读锁时候,去掉前面16位!=0,OwnerThread() = current,说明里面有写锁了,并且是自己。说明一个线程先获取写锁在获取读锁,那么这个线程占据了owenerThread和firstReader或者threadLocalMap。
public class ReadWriteLockTest<E> {
private final Map<String, String> map = new TreeMap<>();
private final ReentrantReadWriteLock1 lock = new ReentrantReadWriteLock1();
//写的时候,不能读不能写。 读的时候,不能写可以读。 //读线程获取锁,其他读线程可以获取锁,写线程不能获取锁
//写线程获取锁,读线程写线程不能获取锁
private final ReentrantReadWriteLock1.ReadLock readLock = lock.readLock();
private final ReentrantReadWriteLock1.WriteLock writeLock = lock.writeLock(); public ReadWriteLockTest() {
} public String write(String key, String value) throws InterruptedException {
writeLock.lock();//写锁是排他的,看到有人获取锁,他不会去获取,他获取了锁别人也不会进来获取锁。
readLock.lock();
// writeLock.lockInterruptibly();
// writeLock.tryLock();
try {
return map.put(key, value);
} finally {
writeLock.unlock();//写锁释放,就唤醒AQS
}
} public String read(String key) throws InterruptedException {
readLock.lock();//获取的是共享锁
// writeLock.lock();
// readLock.lockInterruptibly();
// readLock.tryLock();
try {
return map.get(key);
} finally {
readLock.unlock();//读锁全部释放完了,才会去唤醒AQS
}
} private static ReadWriteLockTest<Integer> tt = new ReadWriteLockTest<Integer>(); public static void main(String[] args) {
new Thread(() -> {
int i = ;
while (true) {
Write w = new Write("写--" + (i++));
w.start();
}
}).start(); new Thread(() -> {
int j = ;
while (true) {
Read s1 = new Read("读--" + (j++));
s1.start();
// Read s2 = new Read("读--" + (j++));
// s2.start();
// Read s3 = new Read("读--" + (j++));
// s3.start();
// s1.interrupt();
// s2.interrupt();
// s3.interrupt();
}
}).start();
}
static int i =;static int j = ;
static class Write extends Thread {
Write(String name) {
super(name);
}
@Override
public void run() {
try {
tt.write((i++)+"",(j++)+"");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} static class Read extends Thread {
Read(String name) {
super(name);
}
@Override
public void run() {
try {
tt.read((i--)+"");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
ReentrantReadWriteLock源码分析的更多相关文章
- 【Java并发编程】16、ReentrantReadWriteLock源码分析
一.前言 在分析了锁框架的其他类之后,下面进入锁框架中最后一个类ReentrantReadWriteLock的分析,它表示可重入读写锁,ReentrantReadWriteLock中包含了两种锁,读锁 ...
- ReentrantReadWriteLock 源码分析
ReentrantReadWriteLock 源码分析: 1:数据结构: 成员变量: private final ReentrantReadWriteLock.ReadLock readerLock ...
- Java并发指南10:Java 读写锁 ReentrantReadWriteLock 源码分析
Java 读写锁 ReentrantReadWriteLock 源码分析 转自:https://www.javadoop.com/post/reentrant-read-write-lock#toc5 ...
- ReentrantReadWriteLock源码分析(一)
此处源码分析,主要是基于读锁,非公平机制,JDK1.8. 问题: 1.ReentrantReadWriteLock是如何创建读锁与写锁? 2.读锁与写锁的区别是什么? 3.锁的重入次数与获取锁的线程数 ...
- Java显式锁学习总结之五:ReentrantReadWriteLock源码分析
概述 我们在介绍AbstractQueuedSynchronizer的时候介绍过,AQS支持独占式同步状态获取/释放.共享式同步状态获取/释放两种模式,对应的典型应用分别是ReentrantLock和 ...
- ReentrantReadWriteLock源码分析笔记
ReentrantReadWriteLock包含两把锁,一是读锁ReadLock, 此乃共享锁, 一是写锁WriteLock, 此乃排它锁. 这两把锁都是基于AQS来实现的. 下面通过源码来看看Ree ...
- ReentrantReadWriteLock 源码分析以及 AQS 共享锁 (二)
前言 上一篇讲解了 AQS 的独占锁部分(参看:ReentrantLock 源码分析以及 AQS (一)),这一篇将介绍 AQS 的共享锁,以及基于共享锁实现读写锁分离的 ReentrantReadW ...
- ReentrantReadWriteLock源码分析及理解
本文结构 读写锁简介:介绍读写锁.读写锁的特性以及类定义信息 公平策略及Sync同步器:介绍读写锁提供的公平策略以及同步器源码分析 读锁:介绍读锁的一些常用操作和读锁的加锁.解锁的源码分析 写锁:介绍 ...
- 多线程之美7一ReentrantReadWriteLock源码分析
目录 前言 在多线程环境下,为了保证线程安全, 我们通常会对共享资源加锁操作,我们常用Synchronized关键字或者ReentrantLock 来实现,这两者加锁方式都是排他锁,即同一时刻最多允许 ...
- Java并发编程笔记之读写锁 ReentrantReadWriteLock 源码分析
我们知道在解决线程安全问题上使用 ReentrantLock 就可以,但是 ReentrantLock 是独占锁,同时只有一个线程可以获取该锁,而实际情况下会有写少读多的场景,显然 Reentrant ...
随机推荐
- 我是如何一步步编码完成万仓网ERP系统的(十四)库存 3.库存日志
https://www.cnblogs.com/smh188/p/11533668.html(我是如何一步步编码完成万仓网ERP系统的(一)系统架构) https://www.cnblogs.com/ ...
- Java自学-I/O 中文问题
Java中的编码中文问题 步骤 1 : 编码概念 计算机存放数据只能存放数字,所有的字符都会被转换为不同的数字. 就像一个棋盘一样,不同的字,处于不同的位置,而不同的位置,有不同的数字编号. 有的棋盘 ...
- XSS相关有效载荷及绕道的备忘录(下)| 文末有打包好的负载
前言: 今天发布的是下半部分 进入正题 过滤的绕过和一些奇异的有效载荷 大小写绕过 <sCrIpt>alert(1)</ScRipt> 绕过标签黑名单 <script x ...
- 高德地图的JSAPI学习笔记【一】
高德地图的项目要做 学习笔记记录下来 一.注册账号并申请Key 二.准备页面写好 1.在页面添加 JS API 的入口脚本标签,并将其中「您申请的key值」替换为您刚刚申请的 key: <sc ...
- uni-app项目记录
1.如何定义一个全局属性 在App.vue 文件中,以 global.属性名= XXX; 定义 在其他页面就以 global.属性名来调用 或者在min.js 中使用 Vue.prototype 挂载 ...
- QTableWidget表格属性
ui->tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); //设置不可编辑 ui->tableWidg ...
- 定时调度之Quartz
工作中我们经常碰到定时或者固定时间点去做一些事情,然后每天到时间点就会去做这样的事情,如果理解这样的场景,我们就要引入今天我们的主角Quartz,其实这个跟数据库的作业类似,但是不仅仅局限于数据库. ...
- Linux 如何用命令查看binlog文件的创建时间
目录 背景 分析 方法 注意 背景 MySQL在26日 16:23:49产生了大量的慢查询,在这段时间内,binlog文件刷新的很快(查看慢日志是mysql DML并发比较多),想知道写完一个binl ...
- hdu1801 01翻转 贪心
题目描述: 对于给出的一个n*m的矩形,它由1和0构成,现在给你一个r*c的矩形空间可以选择,且可以选择无数次(被选中的范围内01翻转),要求问将这个01矩阵全部变成0的最少需要翻多少次,且如果无法实 ...
- Detectron2源码阅读笔记-(三)Dataset pipeline
构建data_loader原理步骤 # engine/default.py from detectron2.data import ( MetadataCatalog, build_detection ...