没有合适的资源?快使用搜索试试~ 我知道了~
深入浅出ReentrantReadWriteLock源码解析.docx
1.该资源内容由用户上传,如若侵权请联系客服进行举报
2.虚拟产品一经售出概不退款(资源遇到问题,请及时私信上传者)
2.虚拟产品一经售出概不退款(资源遇到问题,请及时私信上传者)
版权申诉
0 下载量 143 浏览量
2022-07-10
10:24:19
上传
评论
收藏 35KB DOCX 举报
温馨提示
试读
17页
什么是读锁和写锁 对于资源的访问就两种形式:要么是读操作,要么是写操作。读写锁是将被锁保护的临界资源的读操作和写操作分开,允许同时有多个线程同时对临界资源进行读操作,任意时刻只允许一个线程对资源进行写操作。简单的说,对与读操作采用的是 共享锁 ,对于写操作采用的是 排他锁 。
资源推荐
资源详情
资源评论
深入浅出 ReentrantReadWriteLock 源码解析
读写锁实现逻辑相对比较复杂,但是却是一个经常使用到的功能,希望将
我对 ReentrantReadWriteLock 的源码的理解记录下来,可以对大家有帮助
前提条件
在理解 ReentrantReadWriteLock 时需要具备一些基本的知识
理解 ReentrantLock 的实现原理
ReentrantLock 的实现原理可以参考《深入浅出 ReentrantLock 源码解析》
什么是读锁和写锁
对于资源的访问就两种形式:要么是读操作,要么是写操作。读写锁是将被锁保
护的临界资源的读操作和写操作分开,允许同时有多个线程同时对临界资源进行
读操作,任意时刻只允许一个线程对资源进行写操作。简单的说,对与读操作采
用的是 共享锁 ,对于写操作采用的是 排他锁 。
读写状态的设计
ReentrantReadWriteLock 是用 state 字段来表示读写锁重复获取资源的次数,高
16 位用来标记读锁的同步状态,低 16 位用来标记写锁的同步状态
// 划分的边界线,用 16 位来划分
static final int SHARED_SHIFT = 16;
// 读锁的基本单位,也就是读锁加 1 或者减 1 的基本单位(1 左移 16 位后的值)
static final int SHARED_UNIT = (1 << SHARED_SHIFT);
// 读写锁的最大值(在计算读锁的时候需要先右移 16 位)
static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1;
// 写锁的掩码,state 值与掩码做与运算后得到写锁的真实值
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
// 获取资源被读锁占用的次数
static int sharedCount(int c){
return c >>> SHARED_SHIFT;
}
// 获取资源被写锁占用的次数
static int exclusiveCount(int c){
return c & EXCLUSIVE_MASK;
}
在统计读锁被每个线程持有的次数时,ReentrantReadWriteLock 采用的是
HoldCounter 来实现的,具体如下:
// 持有读锁的线程重入的次数
static final class HoldCounter {
// 重入的次数
int count = 0;
// 持有读锁线程的线程 id
final long tid = getThreadId(Thread.currentThread());
}
/**
* 采用 ThreadLocal 机制,做到线程之间的隔离
*/
static final class ThreadLocalHoldCounter
extends ThreadLocal<HoldCounter> {
public HoldCounter initialValue() {
return new HoldCounter();
}
}
/**
* 线程持有可重入读锁的次数
*/
private transient ThreadLocalHoldCounter readHolds;
/**
* 缓存最后一个成功获取读锁的线程的重入次数,有两方面的好处:
* 1、避免了通过访问 ThreadLocal 来获取读锁的信息,这个优化的前提是
* 假设多数情况下,一个获取读锁的线程,使用完以后就会释放读锁,
* 也就是说最后获取读锁的线程和最先释放读锁的线程大多数情况下是同一个线程
* 2、因为 ThreadLocal 中的 key 是一个弱引用类型,当有一个变量持有 HoldCounter 对象时,
* ThreadLocalHolderCounter 中最后一个获取锁的线程信息不会被 GC 回收掉
*/
private transient HoldCounter cachedHoldCounter;
/**
* 第一个获取读锁的线程,有两方面的考虑:
* 1、记录将共享数量从 0 变成 1 的线程
* 2、对于无竞争的读锁来说进行线程重入次数数据的追踪的成本是比较低的
*/
private transient Thread firstReader = null;
/**
* 第一个获取读锁线程的重入次数,可以参考 firstReader 的解析
*/
private transient int firstReaderHoldCount;
ReentrantReadWriteLock 源码解析
ReentrantReadWriteLock 一共有 5 个内部类,具体如下:
� Sync:公平锁和非公平锁的抽象类
� NonfairSync:非公平锁的具体实现
� FairSync:公平锁的具体实现
� ReadLock:读锁的具体实现
� WriteLock:写锁的具体实现
我们从读锁 ReadLock 和写锁 WriteLock 的源码开始分析,然后顺着这个思路将
整个 ReentrantReadWriteLock 中所有的核心源码(所有的包括内部类)进行分析。
ReadLock 类源码解析
public static class ReadLock implements Lock, java.io.Serializable {
private final Sync sync;
/**
* 通过 ReentrantReadWriteLock 中的公平锁或非公平锁来初始化 sync 变量
*/
protected ReadLock(ReentrantReadWriteLock lock) {
sync = lock.sync;
}
/**
* 阻塞的方式获取锁,因为读锁是共享锁,所以调用 acquireShared 方法
*/
public void lock() {
sync.acquireShared(1);
}
/**
* 可中断且阻塞的方式获取锁
剩余16页未读,继续阅读
资源评论
小兔子平安
- 粉丝: 209
- 资源: 1940
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功