java源码 - ReentrantReadWriteLock介绍
开篇
ReentrantReadWriteLock是Lock的另一种实现方式,我们已经知道了ReentrantLock是一个排他锁,同一时间只允许一个线程访问,而ReentrantReadWriteLock允许多个读线程同时访问,但不允许写线程和读线程、写线程和写线程同时访问。
相对于排他锁,提高了并发性。在实际应用中,大部分情况下对共享数据(如缓存)的访问都是读操作远多于写操作,这时ReentrantReadWriteLock能够提供比排他锁更好的并发性和吞吐量。
这个系列主要是从源码层面讲解ReentrantReadWriteLock,总共分为3篇,欢迎订阅。
- ReentrantReadWriteLock的数据结构介绍
- java源码 - ReentrantReadWriteLock读锁介绍
- java源码 - ReentrantReadWriteLock写锁介绍
ReentrantReadWriteLock类
ReentrantReadWriteLock类包含三个核心变量:
readerLock:读锁。
writerLock:写锁。
sync:可以为公平锁FairSync 或 非公平锁NonfairSync。
ReentrantReadWriteLock类的构造函数执行以下几件事情:
新建锁对象赋予ReentrantReadWriteLock的sync对象。
将ReentrantReadWriteLock对象作为this参数创建读锁ReadLock。
将ReentrantReadWriteLock对象作为this参数创建写锁WriteLock。
在writerLock和ReadLock构造函数中将ReentrantReadWriteLock的sync对象赋值为自身的sync对象,读写锁的操作其实用的就是ReentrantReadWriteLock的sync对象。
public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable { private static final long serialVersionUID = -6992448646407690164L; private final ReentrantReadWriteLock.ReadLock readerLock; private final ReentrantReadWriteLock.WriteLock writerLock; final Sync sync; public ReentrantReadWriteLock() { this(false); } public ReentrantReadWriteLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); readerLock = new ReadLock(this); writerLock = new WriteLock(this); } public ReentrantReadWriteLock.WriteLock writeLock() { return writerLock; } public ReentrantReadWriteLock.ReadLock readLock() { return readerLock; }
ReadLock类
- ReadLock的构造函数入参为ReentrantReadWriteLock对象,通过将ReentrantReadWriteLock对象的sync对象赋值给ReadLock的Sync。
- ReadLock的lock和unlock操作都通过sync对象来实现加锁和解锁
public static class ReadLock implements Lock, java.io.Serializable { private static final long serialVersionUID = -5992448646407690164L; private final Sync sync; protected ReadLock(ReentrantReadWriteLock lock) { sync = lock.sync; } public void lock() { sync.acquireShared(1); } public void lockInterruptibly() throws InterruptedException { sync.acquireSharedInterruptibly(1); } public boolean tryLock() { return sync.tryReadLock(); } public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout)); } public void unlock() { sync.releaseShared(1); } public Condition newCondition() { throw new UnsupportedOperationException(); } }
WriteLock类
- WriteLock的构造函数入参为ReentrantReadWriteLock对象,通过将ReentrantReadWriteLock对象的sync对象赋值给ReadLock的Sync。
- WriteLock的lock和unlock操作都通过sync对象来实现加锁和解锁
public static class WriteLock implements Lock, java.io.Serializable { private static final long serialVersionUID = -4992448646407690164L; private final Sync sync; protected WriteLock(ReentrantReadWriteLock lock) { sync = lock.sync; } public void lock() { sync.acquire(1); } public void lockInterruptibly() throws InterruptedException { sync.acquireInterruptibly(1); } public boolean tryLock( ) { return sync.tryWriteLock(); } public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireNanos(1, unit.toNanos(timeout)); } public void unlock() { sync.release(1); } public Condition newCondition() { return sync.newCondition(); } public boolean isHeldByCurrentThread() { return sync.isHeldExclusively(); } public int getHoldCount() { return sync.getWriteHoldCount(); } }
公平锁和非公平锁类定义
- 公平锁FairSync和非公平锁NonfairSync属于ReentrantReadWriteLock内部定义类,继承自Sync类。
- Sync类继承自AbstractQueuedSynchronizer类,Sync类有一些核心的变量已经加注释。
-
AQS的state变量32位分开高16位为读状态,低16位为写状态。
static final class NonfairSync extends Sync { private static final long serialVersionUID = -8159625535654395037L; final boolean writerShouldBlock() { return false; // writers can always barge } final boolean readerShouldBlock() { return apparentlyFirstQueuedIsExclusive(); } } static final class FairSync extends Sync { private static final long serialVersionUID = -2274990926593161451L; final boolean writerShouldBlock() { return hasQueuedPredecessors(); } final boolean readerShouldBlock() { return hasQueuedPredecessors(); } } abstract static class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = 6317671515068378041L; static final int SHARED_SHIFT = 16; // 高16位记录读状态 static final int SHARED_UNIT = (1 << SHARED_SHIFT); static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1; // 低16位记录写状态 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; } static final class HoldCounter { int count = 0; // Use id, not reference, to avoid garbage retention final long tid = getThreadId(Thread.currentThread()); } static final class ThreadLocalHoldCounter extends ThreadLocal<HoldCounter> { public HoldCounter initialValue() { return new HoldCounter(); } } private transient ThreadLocalHoldCounter readHolds; private transient HoldCounter cachedHoldCounter; private transient Thread firstReader = null; private transient int firstReaderHoldCount; Sync() { readHolds = new ThreadLocalHoldCounter(); setState(getState()); // ensures visibility of readHolds } }
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Python open 读和写
# -*- coding: utf-8 -*- # 测试文件名为: # text.txt # 测试文件内容为: # abcdefg # 每次操作后将文件复原 # r # 以只读方式打开文件,文件不可写 # 要打开的文件不存在时会报错 # 文件的指针将会放在文件的开头 # 这是默认模式 # # file = open('test.txt', 'r') # # FileNotFoundError: [Errno 2] No such file or directory: 'test.txt' # file = open('text.txt', 'r') # print(file.read()) # # abcdefg # file.write('aaa') # # io.UnsupportedOperation: not writable # file.close() # rb # 以二进制格式打开一个文件用于只读,文件不可写 # 要打开的文件不存在时会报错 # 文件指针将会放在文件的开头 # 这是默认模式 # # file = open('test.txt', 'rb') # # Fil...
- 下一篇
第三章 Java的基础程序设计结构
一个简单的 Java 应用程序 访问修饰符 public,private,protected main 方法必须时public修饰的,C#则不必须 数据类型 可以用16进制表示浮点数 可以用2,8,16进制表示整数 Double.POSITIVE_INFINITY,Double.NEGATIVE_INFINITY,DOUBLE.NaN 分别表示正无穷,负无穷,不是数值; if(x==Double.NaN) 永不成立,可以使用Double.isNaN(x)判断 强烈建议不要在程序中使用char,除非必须,可以使用String替代 运算符 整数被0除会抛出异常,浮点数则会得到无穷大或NaN结果 最初的JVM计算浮点时规定必须截断,这样在不同类型机器上可以得到一致的结果,但后来这点被修改, JVM设计者允许中间结果采用扩展的精度. 但是经过strictfp修饰的方法/类必须截断. 使用strictfp的方式可能产生溢出, 但不属于什么大问题. Math.floorMod 是为了解决有关整数余数的问题,即计算机设计中负数的余数为负数导致的不方便 StrictMath类能提供比Math更精确,更...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- CentOS8编译安装MySQL8.0.19
- MySQL8.0.19开启GTID主从同步CentOS8
- SpringBoot2全家桶,快速入门学习开发网站教程
- CentOS7,CentOS8安装Elasticsearch6.8.6
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- Red5直播服务器,属于Java语言的直播服务器
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作