赞
踩
ReentrantReadWriteLock锁是AQS的另一种实现,它做到了可重入、可中断,分为公平和非公平两类实现,并且实现了读锁和写锁两类同时控制。在使用时,读写锁持有的同一个Lock实例,通过控制锁的行为,及CLH节点状态,来操作读锁和写锁,对于写少读多的场景,能提高效率。
由于我对AQS及ReentrantLock的源码已经做过分析,因此本篇文章对经常出现的代码流程介绍的会较为粗略,初次接触ReentrantReadWriteLock源码的同学,建议先从前面的文章看起,这样反而更能清晰的理解。
读写锁ReentrantReadWriteLock,实现接口ReadWriteLock,其内部定义了两个方法,分别获取读锁和写锁。
- public interface ReadWriteLock {
- Lock readLock();
- Lock writeLock();
- }
看一下ReentrantReadWriteLock内部相关实现:
- public class ReentrantReadWriteLock
- implements ReadWriteLock, java.io.Serializable {
-
- 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; }
-
- // ...
- }
与ReadWriteLock接口相关的代码,包含两个锁的实例、一个同步器Sync、两个构造函数,其中无参构造函数默认实现了非公平同步器;初始化两个读写锁实例时,将this传入;接下来看一下读写锁类的实现。
实现Lock接口,内部持有一个Sync实例,由构造函数注入。
- public static class ReadLock implements Lock, java.io.Serializable {
- private final Sync sync;
- protected ReadLock(ReentrantReadWriteLock lock) {
- sync = lock.sync;
- }
- // ...
- }
在翻看ReadLock的实例方法,都是实现的Lock接口,与ReentrantLock相似。而WriteLock的定义与ReadLock差不多,具体分析时再看。
直接进入重点AQS类的实现类Sync,在ReentrantReadWriteLock中,与ReentrantLock类似,分为公平同步器和非公平同步器,并且默认实现的是非公平同步器。
abstract static class Sync extends AbstractQueuedSynchronizer {...}
在Sync中定义了一组常量及方法,用于记录读锁和写锁数量,它们是:
- static final int SHARED_SHIFT = 16; // 共享锁偏移量
- static final int SHARED_UNIT = (1 << SHARED_SHIFT); // 1左移16位,共享锁的位置
- static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1; // 允许申请锁的最大数量
- static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;// 得到低16位补码;这样的int值EXCLUSIVE_MASK的高16位都是0,低16位都是1
-
-
- /** Returns the number of shared holds represented in count */
- static int sharedCount(int c) { return c >>> SHARED_SHIFT; }
- /** Returns the number of exclusive holds represented in count */
- static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
对于AQS的state值,存储的是一个32位int,在ReentrantReadWriteLock中,将高16位记录读锁数量,低16位记录写锁数量。
通过位移等运算,快速的得到需要的值,如sharedCount(int c),传入的c既是state值,通过无符号右移16位,快速得到读锁/共享锁的数量;
而exclusiveCount(int c)方法,传入state的值c,通过与EXCLUSIVE_MASK做&操作,能快速得到低16位的值是多少,也就是写锁/排它锁的数量。
- c = 0110 0011 0000 1001 0000 0000 0000 0011
- c & 0000 0000 0000 0000 1111 1111 1111 1111
- 0000 0000 0000 0000 0000 0000 0000 0011 // 因此有4个排它锁
在这之后,还定义了四个成员变量:
- private transient ThreadLocalHoldCounter readHolds;
- private transient HoldCounter cachedHoldCounter;
- private transient Thread firstReader = null;
- private transient int firstReaderHoldCount;
他们的作用在后面使用到的时候再介绍,这里看类的实现:
- static final class HoldCounter {
- int count = 0;
- final long tid = getThreadId(Thread.currentThread());
- }
- static final class ThreadLocalHoldCounter extends ThreadLocal<HoldCounter> {
- public HoldCounter initialValue() {
- return new HoldCounter();
- }
- }
- static final long getThreadId(Thread thread) {
- return UNSAFE.getLongVolatile(thread, TID_OFFSET);
- }
实现了ThreadLocal<?> ,记录了count和tid两个值,看样子是保持某些信息的。
在Sync中还有两个抽象方法
- abstract boolean readerShouldBlock();
- abstract boolean writerShouldBlock();
既然默认实现的是非公平同步器,那么我们来看一下NofairSync的实现,内容很简单:
- static final class NonfairSync extends Sync {
- final boolean writerShouldBlock() {
- return false; // 永远返回false
- }
- final boolean readerShouldBlock() {
- return apparentlyFirstQueuedIsExclusive(); // 调用一个AQS方法
- }
- }
- final boolean apparentlyFirstQueuedIsExclusive() {
- Node h, s;
- return (h = head) != null &&
- (s = h.next) != null &&
- !s.isShared() &&
- s.thread != null;
- }
同步队列的首个节点不为空、队列不止一个节点、非head节点不是共享(存在排它锁等待)、非head节点的线程不为空。以上条件都满足,则认为当前读锁需要阻塞。
零散的源码介绍的差不多,到这应该已经一头雾水了,没关系,下面开始由读写锁的行为分析源码设计,并将上述内容串起来。
定义了一个Sync类型对象sync,由构造函数传入,也就是这里定义了当前写锁是由“公平同步器实现”还是由“非公平同步器实现”实现的。
- private final Sync sync;
- protected WriteLock(ReentrantReadWriteLock lock) {
- sync = lock.sync;
- }
排它锁加锁流程分析
在WriteLock中,加锁方法直接使用的是sync.acquire(1); 追溯起来就是AQS的acquire()申请流程。
- public void lock() {
- sync.acquire(1);
- }
- public final void acquire(int arg) {
- if (!tryAcquire(arg) &&
- acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
- selfInterrupt();
- }
那么tryAcquire()的实现,则是Sync当中了:
- protected final boolean tryAcquire(int acquires) {
- /*
- * Walkthrough:
- * 1. If read count nonzero or write count nonzero
- * and owner is a different thread, fail.
- * 2. If count would saturate, fail. (This can only
- * happen if count is already nonzero.)
- * 3. Otherwise, this thread is eligible for lock if
- * it is either a reentrant acquire or
- * queue policy allows it. If so, update state
- * and set owner.
- */
- Thread current = Thread.currentThread();
- int c = getState();
- int w = exclusiveCount(c);
- if (c != 0) {
- // (如果 c != 0 并且写锁数量为0,那么读锁数量肯定不为0)
- if (w == 0 || current != getExclusiveOwnerThread())
- return false;
- if (w + exclusiveCount(acquires) > MAX_COUNT)
- throw new Error("Maximum lock count exceeded");
- // Reentrant acquire
- setState(c + acquires);
- return true;
- }
- if (writerShouldBlock() ||
- !compareAndSetState(c, c + acquires))
- return false;
- setExclusiveOwnerThread(current);
- return true;
- }
方法内有大段的注释,翻译一下:
1、如果读锁数量不为0 或者 写锁数量不为零,并且 线程拥有者不是当前线程,获取失败
2、如果锁的数量已经达到最大值,获取失败
3、以上不满足,说明 可以申请锁,如果设置state成功,说明获取成功
这3条,囊括了tryAcquire()方法c!=0的大部分逻辑。
在代码中,if (w == 0 || current != getExclusiveOwnerThread()) 的潜在含义有2点:
1、当读写锁中存在读锁时,是不能直接申请到写锁的;
2、读锁是可以重入的
当c==0的情况下,也就是读写锁都为0,此时做了如下处理:
- if (writerShouldBlock() ||
- !compareAndSetState(c, c + acquires))
- return false;
- setExclusiveOwnerThread(current);
- return true;
由于当前分析的是非公平同步器的实现,因此writerShouldBlock()==false。那么这段的逻辑就是 尝试直接修改state的值,如果设置成功,那么申请锁成功,设置排他线程拥有者、返回true。
在调用完tryAcquire(),后续流程就是AQS标准流程,这个在前文中已经详细描述过,这里不再赘述。
排它锁的tryLock
在WriteLock中实现的tryLock()方法,它的主逻辑是由Sync实现的。
- public boolean tryLock( ) {
- return sync.tryWriteLock();
- }
- final boolean tryWriteLock() {
- Thread current = Thread.currentThread(); // 获取当前线程
- int c = getState();// 获取资源
- if (c != 0) { // 有锁
- int w = exclusiveCount(c); // 计算排它锁数量
- if (w == 0 || current != getExclusiveOwnerThread()) // 与tryAcquire逻辑一致
- return false;
- if (w == MAX_COUNT)
- throw new Error("Maximum lock count exceeded");
- }
- if (!compareAndSetState(c, c + 1))
- return false;
- setExclusiveOwnerThread(current);
- return true;
- }
在tryWriteLock()方法中,相当于是单独执行了一次tryAcquire(),并且只是对state做+1操作。只是不需要考虑排它锁的阻塞情况,这也进一步说明“非公平”的特点。
排它锁带超时的tryLock
带有超时时间的tryLock,实现流程较为复杂,先看一下基本的调用关系:
- public boolean tryLock(long timeout, TimeUnit unit)
- throws InterruptedException {
- return sync.tryAcquireNanos(1, unit.toNanos(timeout));
- }
- public final boolean tryAcquireNanos(int arg, long nanosTimeout) throws InterruptedException {
- if (Thread.interrupted())
- throw new InterruptedException();
- return tryAcquire(arg) ||
- doAcquireNanos(arg, nanosTimeout);
- }
执行同步器的tryAcquireNanos()方法,具体的会执行tryAcquire()尝试直接申请一次锁,如果不成功会执行AQS的doAcquireNanos()。
- private boolean doAcquireNanos(int arg, long nanosTimeout)
- throws InterruptedException {
- if (nanosTimeout <= 0L)
- return false;
- final long deadline = System.nanoTime() + nanosTimeout;
- final Node node = addWaiter(Node.EXCLUSIVE);
- boolean failed = true;
- try {
- for (;;) {
- final Node p = node.predecessor();
- if (p == head && tryAcquire(arg)) {
- setHead(node);
- p.next = null; // help GC
- failed = false;
- return true;
- }
- nanosTimeout = deadline - System.nanoTime();
- if (nanosTimeout <= 0L)
- return false;
- if (shouldParkAfterFailedAcquire(p, node) &&
- nanosTimeout > spinForTimeoutThreshold)
- LockSupport.parkNanos(this, nanosTimeout);
- if (Thread.interrupted())
- throw new InterruptedException();
- }
- } finally {
- if (failed)
- cancelAcquire(node);
- }
- }
这个方法在分析AQS时做过详细分析,这里再写一下粗略的过程:
1、将当前线程封装为node节点,并加入同步队列,计算超时时间点
2、如果node的前置节点是head,则尝试申请锁tryAcquire(),否则进入3
3、当前时间如果未超时,并且剩余时间大于阈值,则将node的线程挂起,等待被唤醒或超时中断
4、被唤醒后重复申请直到申请成功或线程被中断
排它锁解锁流程分析
调用流程与加锁差不多,通过AQS的release实现,并且自定义了tryRelease():
- public void unlock() {
- sync.release(1);
- }
- protected final boolean tryRelease(int releases) {
- if (!isHeldExclusively()) // 根据持有线程,拦截非法释放操作
- throw new IllegalMonitorStateException();
- // 后续代码,都是有效线程内操作
- int nextc = getState() - releases; // 计算释放后资源的值
- boolean free = exclusiveCount(nextc) == 0; // 计算释放后,排它锁的数量
- if (free) // 如果排它锁数量为0,则清空持有的线程
- setExclusiveOwnerThread(null);
- setState(nextc); // 设置资源state的值
- return free; // 返回排它锁是否还持有
- }
- // 当前线程是否持有排它锁
- protected final boolean isHeldExclusively() {
- return getExclusiveOwnerThread() == Thread.currentThread();
- }
由此可知tryRelease()的逻辑很简单,只是操作state的值,以及释放后对 写锁值的检查。
到这里,WriteLock中主要成员已经分析完成。
定义了一个Sync类型对象sync,由构造函数传入,也就是这里定义了当前写锁是由“公平同步器实现”还是由“非公平同步器实现”实现的。
- private final Sync sync;
- protected ReadLock(ReentrantReadWriteLock lock) {
- sync = lock.sync;
- }
共享锁加锁流程分析
在WriteLock中,加锁方法直接使用的是sync.acquire(1); 追溯起来就是AQS的acquireShared()申请流程。
- public void lock() {
- sync.acquireShared(1);
- }
- public final void acquireShared(int arg) {
- if (tryAcquireShared(arg) < 0)
- doAcquireShared(arg);
- }
那么tryAcquireShared()的实现,则是Sync当中了:
- protected final int tryAcquireShared(int unused) {
- /*
- * Walkthrough:
- * 1. If write lock held by another thread, fail.
- * 2. Otherwise, this thread is eligible for
- * lock wrt state, so ask if it should block
- * because of queue policy. If not, try
- * to grant by CASing state and updating count.
- * Note that step does not check for reentrant
- * acquires, which is postponed to full version
- * to avoid having to check hold count in
- * the more typical non-reentrant case.
- * 3. If step 2 fails either because thread
- * apparently not eligible or CAS fails or count
- * saturated, chain to version with full retry loop.
- */
- Thread current = Thread.currentThread();
- int c = getState();
- if (exclusiveCount(c) != 0 &&
- getExclusiveOwnerThread() != current)
- return -1;
- int r = sharedCount(c);
- if (!readerShouldBlock() &&
- r < MAX_COUNT &&
- compareAndSetState(c, c + SHARED_UNIT)) {
- if (r == 0) {
- firstReader = current;
- firstReaderHoldCount = 1;
- } else if (firstReader == current) {
- firstReaderHoldCount++;
- } else {
- HoldCounter rh = cachedHoldCounter;
- if (rh == null || rh.tid != getThreadId(current))
- cachedHoldCounter = rh = readHolds.get();
- else if (rh.count == 0)
- readHolds.set(rh);
- rh.count++;
- }
- return 1;
- }
- return fullTryAcquireShared(current);
- }
同样,方法内有大段的注释,翻译一下:
1、如果存在写锁并被其他线程持有,获取失败
2、读锁是否阻塞、读锁数量是否超过最大值,能否直接修改state
3、如果修改state值成功,根据读锁数量、线程对象等信息,记录一些状态值
其中第二点在修改state时,采用的是compareAndSetState(c, c + SHARED_UNIT),其中c + SHARED_UNIT的含义是:
由于c是当前state的值,它包含读锁(高16位)和写锁(低16位)两部分,如果直接c+1得到的是写锁数量+1,而我们需要对读锁+1时,就要针对高16位进行操作,而SHARED_UNIT=1<<16,它就是读锁的+1标准值。
因此compareAndSetState(c, c + SHARED_UNIT) 的含义类似于compareAndSetState(r, r + 1).
当成个获取到读锁后,需要记录一些信息,在前文我们简单介绍过几个变量及方法,在这里都用到了。
- static final class HoldCounter {
- int count = 0; // 数量
- final long tid = getThreadId(Thread.currentThread()); // 线程id
- }
- static final class ThreadLocalHoldCounter extends ThreadLocal<HoldCounter> {
- public HoldCounter initialValue() {
- return new HoldCounter();
- }
- }
- Sync() {
- readHolds = new ThreadLocalHoldCounter();
- //...
- }
- private transient ThreadLocalHoldCounter readHolds; // 记录线程共享锁信息:HoldCounter
- private transient HoldCounter cachedHoldCounter; // 当前操作读锁的计数器
- private transient Thread firstReader = null; // 首个获取读锁的线程
- private transient int firstReaderHoldCount; // 首个获取读锁的线程的 读锁计数器
- static final long getThreadId(Thread thread) {
- return UNSAFE.getLongVolatile(thread, TID_OFFSET); // 获取线程ID
- }
回到tryAcquireShared()当中:
- if (r == 0) { // 读锁在申请前数量为0
- firstReader = current; // 记录当前线程
- firstReaderHoldCount = 1; // 记录读锁申请数量
- } else if (firstReader == current) { // 如果r!=0 并且第一个读锁申请者是当前线程
- firstReaderHoldCount++; // 累加读锁数量
- } else {
- HoldCounter rh = cachedHoldCounter; // 获取状态缓存对象
- if (rh == null || rh.tid != getThreadId(current)) // 如果线程id与缓存中不一致
- cachedHoldCounter = rh = readHolds.get(); // 从ThreadLocal中获取当前线程的计数器对象
- else if (rh.count == 0)
- readHolds.set(rh); // 设置rh
- rh.count++; // 累加读锁数量
- }
也就是说,共享锁在持有过程中,同步器会记录:
1、持有共享锁的线程、持有的数量
2、首个持有共享锁的线程、持有的数量
在申请到共享锁后,会更新它们的值;猜测释放时,也会更新。
在tryAcquireShared()方法的底部,还有一个fullTryAcquireShared()的调用,如果当前同步队列的头结点不为空、队列中有等待的节点、等待节点申请的锁是排它锁时,那么共享锁的申请需要进行排队,而不是直接申请。而排队申请的处理,就在fullTryAcquireShared()方法中。
- final int fullTryAcquireShared(Thread current) {
- /*
- * This code is in part redundant with that in
- * tryAcquireShared but is simpler overall by not
- * complicating tryAcquireShared with interactions between
- * retries and lazily reading hold counts.
- */
- HoldCounter rh = null;
- for (;;) { // 自旋
- int c = getState();
- if (exclusiveCount(c) != 0) { // 存在排它锁
- if (getExclusiveOwnerThread() != current) // 并不是当前线程持有排它锁
- return -1; // 无法申请读锁
- } else if (readerShouldBlock()) { // 读锁申请是否阻塞,也就是同步队列中是否存在写锁申请
- // 如果申请读锁阻塞了,也就是有写锁在前面排队,那么就要考虑中断申请读锁了。
- if (firstReader == current) {
-
- } else {
- if (rh == null) {
- rh = cachedHoldCounter;
- if (rh == null || rh.tid != getThreadId(current)) {
- rh = readHolds.get();
- if (rh.count == 0)
- readHolds.remove();
- }
- // 清理无效缓存
- }
- if (rh.count == 0) // 如果当前线程读锁计数器为0,说明未申请到锁
- return -1;
- }
- }
- // 整理、统计 读锁计数器
- if (sharedCount(c) == MAX_COUNT)
- throw new Error("Maximum lock count exceeded");
-
- // 这里的else if(xxx)判断,则是整个for(;;)自旋的基础
- if (compareAndSetState(c, c + SHARED_UNIT)) { // 申请读锁资源
- if (sharedCount(c) == 0) { //如果申请前读锁数量为0
- firstReader = current;
- firstReaderHoldCount = 1;
- } else if (firstReader == current) { // 如果首个读锁申请者等于当前线程
- firstReaderHoldCount++;
- } else { // 当前线程并非首个申请读锁的线程,从ThreadLocal对象中获取计数器并更新
- if (rh == null)
- rh = cachedHoldCounter;
- if (rh == null || rh.tid != getThreadId(current))
- rh = readHolds.get();
- else if (rh.count == 0)
- readHolds.set(rh);
- rh.count++;
- cachedHoldCounter = rh; // cache for release
- }
- return 1;
- }
- }
- }
当遇到readerShouldBlock时,ReadLock进入自旋方式,尝试申请锁。
在ReadLock中实现的tryLock()方法,它的主逻辑是由Sync实现的。
- public boolean tryLock() {
- return sync.tryReadLock();
- }
- final boolean tryReadLock() {
- Thread current = Thread.currentThread();
- for (;;) {
- int c = getState();
- if (exclusiveCount(c) != 0 &&
- 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 == 0) {
- firstReader = current;
- firstReaderHoldCount = 1;
- } else if (firstReader == current) {
- firstReaderHoldCount++;
- } else {
- HoldCounter rh = cachedHoldCounter;
- if (rh == null || rh.tid != getThreadId(current))
- cachedHoldCounter = rh = readHolds.get();
- else if (rh.count == 0)
- readHolds.set(rh);
- rh.count++;
- }
- return true;
- }
- }
- }
在tryReadLock()方法中,相当于是单独执行了一次tryAcquireShared(),并且只是对state高16位做+1操作。只是不需要考虑共享锁的阻塞情况,也就没有自旋等待过程,这也进一步说明“非公平”的特点。
共享锁带超时的tryLock
带有超时时间的tryLock,实现流程较为复杂,先看一下基本的调用关系:
- public boolean tryLock(long timeout, TimeUnit unit)
- throws InterruptedException {
- return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
- }
- public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout) throws InterruptedException {
- if (Thread.interrupted())
- throw new InterruptedException();
- return tryAcquireShared(arg) >= 0 ||
- doAcquireSharedNanos(arg, nanosTimeout);
- }
执行同步器的tryAcquireSharedNanos()方法,具体的会执行tryAcquireShared()尝试直接申请一次锁,如果不成功会执行AQS的doAcquireSharedNanos()。
- private boolean doAcquireSharedNanos(int arg, long nanosTimeout)
- throws InterruptedException {
- if (nanosTimeout <= 0L)
- return false;
- final long deadline = System.nanoTime() + nanosTimeout;
- final Node node = addWaiter(Node.SHARED);
- boolean failed = true;
- try {
- for (;;) {
- final Node p = node.predecessor();
- if (p == head) {
- int r = tryAcquireShared(arg);
- if (r >= 0) {
- setHeadAndPropagate(node, r);
- p.next = null; // help GC
- failed = false;
- return true;
- }
- }
- nanosTimeout = deadline - System.nanoTime();
- if (nanosTimeout <= 0L)
- return false;
- if (shouldParkAfterFailedAcquire(p, node) &&
- nanosTimeout > spinForTimeoutThreshold)
- LockSupport.parkNanos(this, nanosTimeout);
- if (Thread.interrupted())
- throw new InterruptedException();
- }
- } finally {
- if (failed)
- cancelAcquire(node);
- }
- }
这个方法在分析AQS时做过详细分析,这里再写一下粗略的过程:
1、将当前线程封装为node节点,并加入同步队列,计算超时时间点
2、如果node的前置节点是head,则尝试申请锁tryAcquireShared(),设置头节点、唤醒后继节点申请共享锁;否则进入3
3、当前时间如果未超时,并且剩余时间大于阈值,则将node的线程挂起,等待被唤醒或超时中断
4、被唤醒后重复申请直到申请成功或线程被中断
共享锁解锁流程分析
ReadLock的解锁通过AQS的releaseShared()实现,并且自定义了tryRelease():
- public void unlock() {
- sync.releaseShared(1);
- }
- protected final boolean tryReleaseShared(int unused) {
- Thread current = Thread.currentThread();
- if (firstReader == current) { // 判断是否为firstReader,设置计数器
- if (firstReaderHoldCount == 1)
- firstReader = null;
- else
- firstReaderHoldCount--;
- } else { // 非首次申请读锁的线程,从ThreadLocal中获取计数器并更新
- HoldCounter rh = cachedHoldCounter;
- if (rh == null || rh.tid != getThreadId(current))
- rh = readHolds.get();
- int count = rh.count;
- if (count <= 1) {
- readHolds.remove();
- if (count <= 0)
- throw unmatchedUnlockException();
- }
- --rh.count;
- }
- for (;;) {
- int c = getState();
- int nextc = c - SHARED_UNIT; // 高16位减一,得到新的读锁数量
- if (compareAndSetState(c, nextc))
- // Releasing the read lock has no effect on readers,
- // but it may allow waiting writers to proceed if
- // both read and write locks are now free.
- return nextc == 0; // 当state的值为0时,读锁完全释放(有读锁时不会存在写锁)
- }
- }
关注方法中的注释。值得注意的是,读锁的释放,会先修改计数器数值,然后自旋方式去释放state资源。
初看ReentrantReadWriteLock类,里面复杂的代码很容易放弃,需要学会对类进行拆解,其核心还是利用AQS来达到读写锁既要分离操作,又要互相影响的目的。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。