ReentrantReadWriteLock源码
@SuppressWarnings("restriction")
public class ReentrantReadWriteLock1 implements ReadWriteLock, java.io.Serializable {
private static final long serialVersionUID = -6992448646407690164L;
private final ReentrantReadWriteLock1.ReadLock readerLock;
private final ReentrantReadWriteLock1.WriteLock writerLock;
final Sync sync; public ReentrantReadWriteLock1() {
this(false);
} public ReentrantReadWriteLock1(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
readerLock = new ReadLock(this);//写锁和读锁,公用同一个Sync,也就是同一个AQS队列,
writerLock = new WriteLock(this);
} public ReentrantReadWriteLock1.WriteLock writeLock() {
return writerLock;
} public ReentrantReadWriteLock1.ReadLock readLock() {
return readerLock;
} abstract static class Sync extends AbstractQueuedSynchronizer1 {//ReentrantLock有自己的Sync,都继承AQS类,
private static final long serialVersionUID = 6317671515068378041L; static final int SHARED_SHIFT = ;
static final int SHARED_UNIT = ( << SHARED_SHIFT);// 2^16
static final int MAX_COUNT = ( << SHARED_SHIFT) - ;// 2^16-1
static final int EXCLUSIVE_MASK = ( << SHARED_SHIFT) - ;// 2^16-1 static int sharedCount(int c) {//小于2^16=0,等于2^16=1,大于2^16>1,共享锁最大共享线程数=2^16-1,
return c >>> SHARED_SHIFT;// 右移16位,
} static int exclusiveCount(int c) {
return c & EXCLUSIVE_MASK;// 去掉前面16位,
} static final class HoldCounter {
int count = ;
final long tid = getThreadId(Thread.currentThread());
} static final class ThreadLocalHoldCounter extends ThreadLocal<HoldCounter> {
public HoldCounter initialValue() {
return new HoldCounter();//ThreadLocalHoldCounter作为key,new HoldCounter()作为value,
}
} //当前线程持有的可重入读锁的数量。构造函数中初始化。每当线程的读计数下降到0时删除。
private transient ThreadLocalHoldCounter readHolds;//只有一个 private transient HoldCounter cachedHoldCounter;//多个 private transient Thread firstReader = null;
private transient int firstReaderHoldCount; Sync() {
readHolds = new ThreadLocalHoldCounter();//只有一个
setState(getState());
} abstract boolean readerShouldBlock();
abstract boolean writerShouldBlock(); protected final boolean tryRelease(int releases) {//写锁释放
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
int nextc = getState() - releases;// 状态变量的值减1
boolean free = exclusiveCount(nextc) == ;//写锁=0
if (free)//getState()-releases == 0
setExclusiveOwnerThread(null);
setState(nextc);
return free;
} protected final boolean tryAcquire(int acquires) {//WriteLock获取锁,多线程访问
Thread current = Thread.currentThread();
int c = getState();
int w = exclusiveCount(c);//w=0则C=2^16,w!=0则C<2^16,写锁被获取的次数 if (c != ) {//锁里面有线程了重入锁,写锁只要看见state里面有线程就去排队(可能里面有读锁或者写锁), // c!=0,w=0:说明C=2^16的整数倍,说明有读线程获取了锁,
if (w == || current != getExclusiveOwnerThread()) // c!=0,w=0,说明有读锁进去,写锁不进去,其它线程获取了互斥锁(写锁)
return false;//获取锁失败去排队 /*单线程进来,线程安全的。 */ //w!=0&¤t=OwnerThread,MAX_COUNT=2^16-1,就去加值,
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
//w!=0&¤t=OwnerThread,MAX_COUNT=2^16-1,就去加值,
setState(c + acquires);//acquires每次都是从1开始的,C从0开始,所以c,w,acquires不可能大于2^16。
return true;
}
//c=0,锁里面没有线程,就要去抢锁。
//writerShouldBlock:非公平返回false,就去获取锁。
//writerShouldBlock:公平,返回true排队,返回false,就去获取锁。
//获取state成功设置owenerThread=自己,不去排队,获取state失败,去排队。
if (writerShouldBlock() || !compareAndSetState(c, c + acquires))
return false; /*单线程进来,线程安全的。
compareAndSetState(c, c+acquires)可以作为一把锁,synchronized,
别的线程要想进到compareAndSetState包裹的代码里面去,必须重新获取新的c=c+acquires,但是进去if(c!=0)里面去了。
*/ setExclusiveOwnerThread(current);//获得锁。
return true;
} protected final boolean tryReleaseShared(int unused) {// 读锁释放(共享锁),unused没有使用
Thread current = Thread.currentThread();
if (firstReader == current) {
// 如果第一个读者(读线程)是当前线程
// 就把它重入的次数减1
// 如果减到0了就把第一个读者置为空
if (firstReaderHoldCount == )
firstReader = null;
else
firstReaderHoldCount--;
} else {
// 如果第一个读者不是当前线程,一样地,把它重入的次数减1
HoldCounter rh = cachedHoldCounter;//最后获取读锁的HoldCounter
if (rh == null || rh.tid != getThreadId(current))
rh = readHolds.get();//get方法没有时候,就回去创建,有就返回。返回当前线程threadLcoalMap里面的那行记录
int count = rh.count;
if (count <= ) {
readHolds.remove();
if (count <= )
throw unmatchedUnlockException();
}
--rh.count;
}
for (;;) {// 共享锁获取的次数减1,如果减为0了说明完全释放了,才返回true
int c = getState();
int nextc = c - SHARED_UNIT;//减去65536
if (compareAndSetState(c, nextc))
return nextc == ;//读锁完全释放了,
}
} private IllegalMonitorStateException unmatchedUnlockException() {
return new IllegalMonitorStateException("attempt to unlock read lock, not locked by current thread");
} //读锁每次进来加65536,写锁每次进来加1,
protected final int tryAcquireShared(int unused) {//ReadLock获取锁,走这个方法,并发问题,unused没有使用
// 在读写锁模式下,高16位存储的是共享锁(读锁)被获取的次数,低16位存储的是互斥锁(写锁)被获取的次数
Thread current = Thread.currentThread();
int c = getState();//state在AQS类里面,读锁写锁,公用一个Sync AQS state,写锁只能一个进去,另一个写锁进不去,读锁也进不去,
if (exclusiveCount(c) != /*去掉前面16位,*/ && getExclusiveOwnerThread() != current)//state!=0,并且 当前线程没有获取锁。如果写线程获取了锁,state+1就返回-1去排队。
return -;
int r = sharedCount(c);//右移16位, 读锁被获取的次数
//多线程可以进来
if (!readerShouldBlock()/* AQS队列第一个节点写线程跳过,没有第一个节点或者第一个是读线程就进去 */ && r < MAX_COUNT
&& compareAndSetState(c, c + SHARED_UNIT)/* c每次增加65536 */) {
//可以多线程进来,AQS队列没有节点 并且 c是2^16的整数倍=0就是没有写锁,第一个线程进来后只要后面的线程重新获取c就可以进来, // 注意下面对firstReader的处理:firstReader是不会放到readHolds里的
// 这样,在读锁只有一个的情况下,就避免了查找readHolds。
if (r == ) {//r=0,c<2^16,没有读锁
firstReader = current;//获取读锁的线程,Thread
firstReaderHoldCount = ;
} else if (firstReader == current) {//重入锁
firstReaderHoldCount++;
} else {
//先查缓存
HoldCounter rh = cachedHoldCounter;//HoldCounter,缓存前一个线程的HoldCounter(线程id和获取锁次数)
if (rh == null || rh.tid != getThreadId(current))
//ThreadLocal里面get,ThreadLocalHoldCounter。
//当前线程的threadLocals属性的threadLocalMap里面加了一行记录(key=readHolds[ThreadLocalHoldCounter],value=cachedHoldCounter[HoldCounter]),
//其他线程也会在他的threadLocals的threadLocalMap里面加一行记录(key=readHolds[ThreadLocalHoldCounter],value=cachedHoldCounter[HoldCounter]),
//每个线程里面只有一行记录,ThreadLocal是公用的,因为只有一个ThreadLocal,value放的是线程的id和计数器。就这样线程就获取了锁,
cachedHoldCounter = rh = readHolds.get();
else if (rh.count == )//当前线程就是上一次线程,就修改thradLocals
readHolds.set(rh);
rh.count++;//多个读,只有一个firstReader,其余的都是在线程里面的threadLocals里面加了一行记录,重入的次数加1(初始次数为0)
}
return ;//获取了锁
}
//有人在排队
return fullTryAcquireShared(current);
} //在tryAcquireShared中经行了一次快速锁获取,但是由于CAS只能允许一个线程获取锁成功,且读锁是共享的,
//可能存在其他仍然可以获取锁的线程,所以在函数末尾调用函数fullTryAcquireShared来进行死循环的获取锁,
final int fullTryAcquireShared(Thread current) {//获取读锁
HoldCounter rh = null;
for (;;) {//死循环
int c = getState();
if (exclusiveCount(c) != ) {//去掉前面16位!= 0
if (getExclusiveOwnerThread() != current)//相等,就是先获取写锁在获取读锁,
return -;//排队
// 否则,我们持有独占锁;在这里阻塞将导致死锁。
} else if (readerShouldBlock()) {//去掉前面16位= 0,并且AQS队列有第一个节点是写锁不是读锁,
// 确保我们没有重新获取读锁
if (firstReader == current) {
// assert firstReaderHoldCount > 0;
} else {
if (rh == null) {
rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current)) {
rh = readHolds.get();//设置当前线程的threadLocals,key还是readHolds同一个ThreadLocal,
if (rh.count == )//!=0,就说明这个线程之前已经获取一次锁成功了,
readHolds.remove();//从当前线程threadLocals中移除这行记录,
}
}
if (rh.count == )
return -;//排队,
}
} //AQS没有节点,有第一个节点,第一个节点只能是读节点,就去设置threadLcoalMap并且获取锁,
if (sharedCount(c) == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
if (compareAndSetState(c, c + SHARED_UNIT)) {
if (sharedCount(c) == ) {//=0,就说明没有读线程,
firstReader = current;
firstReaderHoldCount = ;
} else if (firstReader == current) {
firstReaderHoldCount++;
} else {
if (rh == null)
rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
rh = readHolds.get();
else if (rh.count == )
readHolds.set(rh);
rh.count++;
cachedHoldCounter = rh; // cache for release
}
return ;//获取了锁
}
}
} final boolean tryWriteLock() {
Thread current = Thread.currentThread();
int c = getState();
if (c != ) {
int w = exclusiveCount(c);
if (w == || current != getExclusiveOwnerThread())
return false;
if (w == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
}
//c=0
if (!compareAndSetState(c, c + ))
return false;
setExclusiveOwnerThread(current);
return true;
} final boolean tryReadLock() {
Thread current = Thread.currentThread();
for (;;) {
int c = getState();
if (exclusiveCount(c) != && getExclusiveOwnerThread() != current)
return false;
int r = sharedCount(c);
if (r == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
if (compareAndSetState(c, c + SHARED_UNIT)) {
if (r == ) {
firstReader = current;
firstReaderHoldCount = ;
} else if (firstReader == current) {
firstReaderHoldCount++;
} else {
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
cachedHoldCounter = rh = readHolds.get();
else if (rh.count == )
readHolds.set(rh);
rh.count++;
}
return true;
}
}
} protected final boolean isHeldExclusively() {
return getExclusiveOwnerThread() == Thread.currentThread();
} final ConditionObject newCondition() {
return new ConditionObject();
} final Thread getOwner() {
return ((exclusiveCount(getState()) == ) ? null : getExclusiveOwnerThread());
} final int getReadLockCount() {
return sharedCount(getState());
} final boolean isWriteLocked() {
return exclusiveCount(getState()) != ;
} final int getWriteHoldCount() {
return isHeldExclusively() ? exclusiveCount(getState()) : ;
} final int getReadHoldCount() {
if (getReadLockCount() == )
return ; Thread current = Thread.currentThread();
if (firstReader == current)
return firstReaderHoldCount; HoldCounter rh = cachedHoldCounter;
if (rh != null && rh.tid == getThreadId(current))
return rh.count; int count = readHolds.get().count;
if (count == )
readHolds.remove();
return count;
} private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
readHolds = new ThreadLocalHoldCounter();
setState(); // reset to unlocked state
} final int getCount() {
return getState();
}
} static final class NonfairSync extends Sync {
private static final long serialVersionUID = -8159625535654395037L; final boolean writerShouldBlock() {//false获取锁。
return false;
} final boolean readerShouldBlock() {// 非公平读是否要阻塞,true排队,false获取锁。
return apparentlyFirstQueuedIsExclusive();//AQS队列有第一个节点是写锁不是读锁,
}
} static final class FairSync extends Sync {
private static final long serialVersionUID = -2274990926593161451L; final boolean writerShouldBlock() {// 公平写是否要阻塞,true排队,false获取锁。
return hasQueuedPredecessors();
} final boolean readerShouldBlock() {// 公平读是否要阻塞,true排队,false获取锁。
return hasQueuedPredecessors();
}
} public static class ReadLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = -5992448646407690164L;
private final Sync sync; protected ReadLock(ReentrantReadWriteLock1 lock) {// 外部类this
sync = lock.sync;
} public void lock() {//获取读锁,获取的是共享锁,调用sync.acquireShared(AQS的方法),写锁调用sync.acquire(AQS的方法)
try {
sync.acquireShared();
} catch (InterruptedException e) {
e.printStackTrace();
}
} public void lockInterruptibly() throws InterruptedException {
sync.acquireSharedInterruptibly();
} public boolean tryLock() {
return sync.tryReadLock();
} public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireSharedNanos(, unit.toNanos(timeout));
} public void unlock() {
sync.releaseShared();
} public Condition newCondition() {
throw new UnsupportedOperationException();
} public String toString() {
int r = sync.getReadLockCount();
return super.toString() + "[Read locks = " + r + "]";
}
} public static class WriteLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = -4992448646407690164L;
private final Sync sync; protected WriteLock(ReentrantReadWriteLock1 lock) {
sync = lock.sync;
} public void lock() {//获取写锁,写锁的获取逻辑和ReentrantLock一样,失败的加入AQS队列,
try {//读锁调用sync.acquireShared(AQS的方法),写锁调用sync.acquire(AQS的方法)
sync.acquire();//尝试获取锁,获取失败就在AQS阻塞排队
} catch (InterruptedException e) {
e.printStackTrace();
}
} public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly();
} public boolean tryLock() {
return sync.tryWriteLock();//获取读锁,不在AQS类里面,在本Sync类里面,
} public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireNanos(, unit.toNanos(timeout));
} public void unlock() {
sync.release();//写锁释放,线程安全,唤醒AQS头结点,
} public Condition newCondition() {
return sync.newCondition();
} public String toString() {
Thread o = sync.getOwner();
return super.toString() + ((o == null) ? "[Unlocked]" : "[Locked by thread " + o.getName() + "]");
} public boolean isHeldByCurrentThread() {
return sync.isHeldExclusively();
} public int getHoldCount() {
return sync.getWriteHoldCount();
}
} public final boolean isFair() {
return sync instanceof FairSync;
} protected Thread getOwner() {
return sync.getOwner();
} public int getReadLockCount() {
return sync.getReadLockCount();
} public boolean isWriteLocked() {
return sync.isWriteLocked();
} public boolean isWriteLockedByCurrentThread() {
return sync.isHeldExclusively();
} public int getWriteHoldCount() {
return sync.getWriteHoldCount();
} public int getReadHoldCount() {
return sync.getReadHoldCount();
} protected Collection<Thread> getQueuedWriterThreads() {
return sync.getExclusiveQueuedThreads();
} protected Collection<Thread> getQueuedReaderThreads() {
return sync.getSharedQueuedThreads();
} public final boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
} public final boolean hasQueuedThread(Thread thread) {
return sync.isQueued(thread);
} public final int getQueueLength() {
return sync.getQueueLength();
} protected Collection<Thread> getQueuedThreads() {
return sync.getQueuedThreads();
} public boolean hasWaiters(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer1.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.hasWaiters((AbstractQueuedSynchronizer1.ConditionObject) condition);
} public int getWaitQueueLength(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer1.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.getWaitQueueLength((AbstractQueuedSynchronizer1.ConditionObject) condition);
} protected Collection<Thread> getWaitingThreads(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer1.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.getWaitingThreads((AbstractQueuedSynchronizer1.ConditionObject) condition);
} public String toString() {
int c = sync.getCount();
int w = Sync.exclusiveCount(c);
int r = Sync.sharedCount(c); return super.toString() + "[Write locks = " + w + ", Read locks = " + r + "]";
} // Thread Id可以被重写
static final long getThreadId(Thread thread) {
return UNSAFE.getLongVolatile(thread, TID_OFFSET);
} private static final sun.misc.Unsafe UNSAFE;
private static final long TID_OFFSET;
static {
try {
UNSAFE = java.security.AccessController
.doPrivileged(new java.security.PrivilegedExceptionAction<sun.misc.Unsafe>() {
public sun.misc.Unsafe run() throws Exception {
Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class;
for (java.lang.reflect.Field f : k.getDeclaredFields()) {
f.setAccessible(true);
Object x = f.get(null);
if (k.isInstance(x))
return k.cast(x);
}
throw new NoSuchFieldError("the Unsafe");
}
});
Class<?> tk = Thread.class;
TID_OFFSET = UNSAFE.objectFieldOffset(tk.getDeclaredField("tid"));
} catch (Exception e) {
throw new Error(e);
}
} }
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源码解析
读写锁实现逻辑相对比较复杂,但是却是一个经常使用到的功能,希望将我对ReentrantReadWriteLock的源码的理解记录下来,可以对大家有帮助 前提条件 在理解ReentrantReadWri ...
- Java并发编程笔记之读写锁 ReentrantReadWriteLock 源码分析
我们知道在解决线程安全问题上使用 ReentrantLock 就可以,但是 ReentrantLock 是独占锁,同时只有一个线程可以获取该锁,而实际情况下会有写少读多的场景,显然 Reentrant ...
- ReentrantReadWriteLock源码分析(一)
此处源码分析,主要是基于读锁,非公平机制,JDK1.8. 问题: 1.ReentrantReadWriteLock是如何创建读锁与写锁? 2.读锁与写锁的区别是什么? 3.锁的重入次数与获取锁的线程数 ...
- Java显式锁学习总结之五:ReentrantReadWriteLock源码分析
概述 我们在介绍AbstractQueuedSynchronizer的时候介绍过,AQS支持独占式同步状态获取/释放.共享式同步状态获取/释放两种模式,对应的典型应用分别是ReentrantLock和 ...
- Java多线程——ReentrantReadWriteLock源码阅读
之前讲了<AQS源码阅读>和<ReentrantLock源码阅读>,本次将延续阅读下ReentrantReadWriteLock,建议没看过之前两篇文章的,先大概了解下,有些内 ...
- 死磕 java同步系列之ReentrantReadWriteLock源码解析
问题 (1)读写锁是什么? (2)读写锁具有哪些特性? (3)ReentrantReadWriteLock是怎么实现读写锁的? (4)如何使用ReentrantReadWriteLock实现高效安全的 ...
- ReentrantReadWriteLock源码分析笔记
ReentrantReadWriteLock包含两把锁,一是读锁ReadLock, 此乃共享锁, 一是写锁WriteLock, 此乃排它锁. 这两把锁都是基于AQS来实现的. 下面通过源码来看看Ree ...
随机推荐
- ASP.NET Core部署IIS问题总结
部署准备工作 1.服务器开启添加IIS相关功能 1.1. 点击windows搜索到 “启用或关闭windows功能” 1.2 选择添加IIS的部分功能, 如下图所示 2.进入IIS,添加已经发布的 ...
- PIE 插件式开发小笔记__PIESDK学习体会
基于PIE.NET-SDK插件式二次开发文档笔记: PIE 插件式开发配置文件: 它里面一行如下: 理解上一行'Item'关系-> library:为插件类名(程序集名称+后缀 ...
- PHP错误日志相关
https://cloud.tencent.com/developer/article/1167951 php错误日志总结 https://cloud.tencent.com/developer/ ...
- 微信小程序环境配置和开发!!
1.登陆微信公众平台小程序,下载 普通小程序开发者工具.或者 小游戏开发者工具. 2.新建项目需要填以下几点,然后初始demo如下,注意rpx是分成750份的单位. 3.点击预览,用微信扫描二维码,代 ...
- JavaScript之二十三种设计模式
23种JavaScript设计模式 原文链接:https://boostlog.io/@sonuton/23-javascript-design-patterns-5adb006847018500 ...
- 百度地图API操作实战
什么是百度地图API: 百度地图API是为开发者免费提供的一套基于百度地图服务的应用接口,包括JavaScript API,web服务API,Android等多种开发工具服务.提供基本地图展现,搜索, ...
- 安装Python,输入pip命令报错———pip Fatal error in launcher: Unable to create process using
今天把Python的安装位置也从C盘剪切到了D盘, 然后修改了Path环境变量中对应的盘符:D:\Python27\;D:\Python27\Scripts; 不管是在哪个目录,Python可以执行了 ...
- Mysql高性能优化规范
数据库命令规范 所有数据库对象名称必须使用小写字母并用下划线分割 所有数据库对象名称禁止使用mysql保留关键字(如果表名中包含关键字查询时,需要将其用单引号括起来) 数据库对象的命名要能做到见名识意 ...
- Spring Boot 2 整合 Dubbo 框架 ,实现 RPC 服务远程调用
一.Dubbo框架简介 1.框架依赖 图例说明: 1)图中小方块 Protocol, Cluster, Proxy, Service, Container, Registry, Monitor 代 ...
- mysql数据库之主从复制+双主--MMM
mysql复制:在主数据库中,前端用户每执行一个写操作/语句,都会在二进制日志中保存一个事件,把这个事件从mysql的服务器中3306端口发送给从服务器,从服务器把这个事件接受下来,接受下来先保存在本 ...