一、继承关系
public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable
实现了ReadWriteLock接口和Serializable接口
ReadWriteLock接口内部包含两个抽象方法:
Lock readLock();//返回一个读锁(共享锁)
Lock writeLock();//返回一个写锁(独占锁)
说明:
(1)ReentrantReadWriteLock中包含了读锁和写锁,分别有公平和非公平两种实现。
(2)该类中包含一个继承了AQS的Sync类型的对象,Sync抽象类有两个子类NonfairSync和FairSync,分别实现公平和非公平两种方式。在new ReentrantReadWriteLock对象时可以传递一个boolean类型的参数指定是读写锁是采用公平还是非公平策略实现。
(3)readLock和writeLock中都包含一个成员变量sync,lock和unlock都是通过调用sync对象的相应方法实现。
二、成员变量
/** Inner class providing readlock */
private final ReentrantReadWriteLock.ReadLock readerLock;//读锁
/** Inner class providing writelock */
private final ReentrantReadWriteLock.WriteLock writerLock;//写锁
/** Performs all synchronization mechanics */
final Sync sync;//AQS子类
三、内部类
(1)Sync:继承自AQS
总结:
写线程获取锁成功情况:
(1)有线程独占锁(可能该线程还共享的占有锁),且该线程是自身,这时写线程获取锁成功。
(2)没有线程占有锁,锁处于空闲状态,此时该写线程可能占有锁成功。
(3)当只有读线程占有锁(无论是否是自身),或者有线程独占锁但不是自身,这两种情况获取锁失败。
读线程获取锁成功情况:
(1)有写线程占有锁,但该写线程是自身,获取锁成功
(2)没有写线程占有锁,获取锁成功
(3)当有写线程占有锁,且不是自身时,获取锁失败。
关于锁降级:写锁--->读锁
当该线程的写线程占有锁,该线程又想以读方式占有锁,此时获取成功,该线程的分别以读和写的方式占有锁,若此时,该线程写方式释放了锁,则此时锁由写锁降级成了读锁。(顺序:写--读---写释放)
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 6317671515068378041L;
//由于AQS中state只有一个变量保存锁的数目,这里有两种锁的数目需要保存,故采用将state划分为高16位和低16位,高位保存共享锁的数目,低位保存独占锁的数目
static final int SHARED_SHIFT = 16;
static final int SHARED_UNIT = (1 << SHARED_SHIFT);//1左移16位为0x100,共享锁的最小单位
static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1;//共享锁和独占锁的最大数目为0xff
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;//独占锁的掩码
/** Returns the number of shared holds represented in count */
static int sharedCount(int c) { return c >>> SHARED_SHIFT; }//右移16位,获取高位表示的共享锁的数目
/** Returns the number of exclusive holds represented in count */
static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }//与0xff进行&操作,获得低位的独占锁的数目
/**
* A counter for per-thread read hold counts.
* Maintained as a ThreadLocal; cached in cachedHoldCounter
*/
//每一个线程拥有锁的数目
static final class HoldCounter {
int count = 0;
// Use id, not reference, to avoid garbage retention
final long tid = getThreadId(Thread.currentThread());
}
/**
* ThreadLocal subclass. Easiest to explicitly define for sake
* of deserialization mechanics.
*/
//将holdCounter与Thread结合起来
static final class ThreadLocalHoldCounter
extends ThreadLocal<HoldCounter> {
public HoldCounter initialValue() {
return new HoldCounter();
}
}
/**
* The number of reentrant read locks held by current thread.
* Initialized only in constructor and readObject.
* Removed whenever a thread's read hold count drops to 0.
*/
private transient ThreadLocalHoldCounter readHolds;
/**
* The hold count of the last thread to successfully acquire
* readLock. This saves ThreadLocal lookup in the common case
* where the next thread to release is the last one to
* acquire. This is non-volatile since it is just used
* as a heuristic, and would be great for threads to cache.
*
* <p>Can outlive the Thread for which it is caching the read
*