摘要:类顾名思义是一种读写锁它是接口的直接实现该类在内部实现了具体独占锁特点的写锁以及具有共享锁特点的读锁和一样类也是通过定义内部类实现框架的来实现独占共享的功能属于排他锁这些锁在同一时刻只允许一个线程进行访问但是在大多数场景下大部分时间都是提供
ReentrantReadWriteLock 类, 顾名思义, 是一种读写锁, 它是 ReadWriteLock 接口的直接实现, 该类在内部实现了具体独占锁特点的写锁, 以及具有共享锁特点的读锁, 和 ReentrantLock 一样, ReentrantReadWriteLock 类也是通过定义内部类实现AQS框架的API来实现独占/共享的功能.
ReentrantLock 属于排他锁, 这些锁在同一时刻只允许一个线程进行访问, 但是在大多数场景下, 大部分时间都是提供读服务, 而写服务占有的时间较少. 而且, 读服务不存在数据竞争问题, 如果一个线程在读时禁止其他线程读势必会导致性能降低. 所以就提供了读写锁.
读写锁维护着一对锁, 一个读锁和一个写锁. 通过分离读锁和写锁, 使得并发性比一般的排他锁有了较大的提升:
在同一时间, 可以允许多个读线程同时访问.
但是, 在写线程访问时, 所有读线程和写线程都会被阻塞.
读写锁的主要特性:
公平性:支持公平性和非公平性.
重入性:支持重入. 读写锁最多支持 65535 个递归写入锁和 65535 个递归读取锁.
锁降级:遵循获取写锁, 再获取读锁, 最后释放写锁的次序, 如此写锁能够降级成为读锁.
ReadWriteLock读写锁 ReentrantReadWriteLock 实现接口 ReadWriteLock, 该接口维护了一对相关的锁, 一个用于只读操作, 另一个用于写入操作. 只要没有 writer, 读取锁可以由多个 reader 线程同时保持. 写入锁是独占的.
public interface ReadWriteLock { Lock readLock(); Lock writeLock(); }
ReadWriteLock 定义了两个方法. readLock() 返回用于读操作的锁, writeLock() 返回用于写操作的锁.
ReentrantReadWriteLockjava.util.concurrent.locks.ReentrantReadWriteLock 定义如下.
/** 内部类 读锁 */ private final ReentrantReadWriteLock.ReadLock readerLock; /** 内部类 写锁 */ private final ReentrantReadWriteLock.WriteLock writerLock; final Sync sync; /** 使用默认(非公平)的排序属性创建一个新的 ReentrantReadWriteLock */ public ReentrantReadWriteLock() { this(false); } /** 使用给定的公平策略创建一个新的 ReentrantReadWriteLock */ public ReentrantReadWriteLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); readerLock = new ReadLock(this); writerLock = new WriteLock(this); } /** 返回用于写入操作的锁 */ @Override public ReentrantReadWriteLock.WriteLock writeLock() { return writerLock; } /** 返回用于读取操作的锁 */ @Override public ReentrantReadWriteLock.ReadLock readLock() { return readerLock; } abstract static class Sync extends AbstractQueuedSynchronizer { /** * 省略其余源代码 */ } public static class WriteLock implements Lock, java.io.Serializable { /** * 省略其余源代码 */ } public static class ReadLock implements Lock, java.io.Serializable { /** * 省略其余源代码 */ }
ReentrantReadWriteLock 与 ReentrantLock 一样, 其锁主体依然是 Sync, 它的读锁、写锁都是依靠 Sync 来实现的.
所以 ReentrantReadWriteLock 实际上只有一个锁, 只是在获取读取锁和写入锁的方式上不一样而已, 它的读写锁其实就是两个类: ReadLock、writeLock, 这两个类都是lock实现.
在 ReentrantLock 中, 使用 Sync ( 实际是 AQS ) 的 int 类型的 state 来表示同步状态, 表示锁被一个线程重复获取的次数.
但是, 读写锁 ReentrantReadWriteLock 内部维护着一对读写锁, 如果要用一个变量维护多种状态, 需要采用 “按位切割使用” 的方式来维护这个变量, 将其切分为两部分: 高16为表示读, 低16为表示写.
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/77515.html
摘要:我们知道,的作用其实是对类的和的增强,是为了让线程在指定对象上等待,是一种线程之间进行协调的工具。当线程调用对象的方法时,必须拿到和这个对象关联的锁。 showImg(https://segmentfault.com/img/remote/1460000016012566); 本文首发于一世流云的专栏:https://segmentfault.com/blog... 一、Reentr...
摘要:不同的是它还多了内部类和内部类,以及读写对应的成员变量和方法。另外是给和内部类使用的。内部类前面说到的操作是分配到里面执行的。他们都是接口的实现,所以其实最像应该是这个两个内部类。而且大体上也没什么差异,也是用的内部类。 之前讲了《AQS源码阅读》和《ReentrantLock源码阅读》,本次将延续阅读下ReentrantReadWriteLock,建议没看过之前两篇文章的,先大概了解...
摘要:关于,最后有两点规律需要注意当的等待队列队首结点是共享结点,说明当前写锁被占用,当写锁释放时,会以传播的方式唤醒头结点之后紧邻的各个共享结点。当的等待队列队首结点是独占结点,说明当前读锁被使用,当读锁释放归零后,会唤醒队首的独占结点。 showImg(https://segmentfault.com/img/remote/1460000016012293); 本文首发于一世流云的专栏:...
摘要:前言回顾前面多线程三分钟就可以入个门了源码剖析多线程基础必要知识点看了学习多线程事半功倍锁机制了解一下简简单单过一遍只有光头才能变强上一篇已经将锁的基础简单地过了一遍了,因此本篇主要是讲解锁主要的两个子类那么接下来我们就开始吧一锁首先我们来 前言 回顾前面: 多线程三分钟就可以入个门了! Thread源码剖析 多线程基础必要知识点!看了学习多线程事半功倍 Java锁机制了解一下 AQ...
摘要:所以就有了读写锁。只要没有,读取锁可以由多个线程同时保持。其读写锁为两个内部类都实现了接口。读写锁同样依赖自定义同步器来实现同步状态的,而读写状态就是其自定义同步器的状态。判断申请写锁数量是否超标超标则直接异常,反之则设置共享状态。 一、写在前面 在上篇我们聊到了可重入锁(排它锁)ReentrantLcok ,具体参见《J.U.C|可重入锁ReentrantLock》 Reentra...
阅读 3829·2021-11-25 09:43
阅读 2173·2021-11-23 10:11
阅读 1399·2021-09-29 09:35
阅读 1312·2021-09-24 10:31
阅读 2037·2019-08-30 15:48
阅读 2355·2019-08-29 15:28
阅读 427·2019-08-29 12:36
阅读 3492·2019-08-28 18:12