前言
ReentrantReadWriteLock是Java中的一种读写锁,它允许多个线程同时读取共享资源,但是只允许一个线程进行写入操作。在读多写少的场景中,读写锁可以提高程序的并发性能。
ReentrantReadWriteLock的实现是基于AbstractQueuedSynchronizer (AQS)的同步器实现的。通过AQS的内部状态和线程的协作,ReentrantReadWriteLock实现了对共享资源的读取和写入操作的互斥和排他。
源码实现:
1. 构造函数
ReentrantReadWriteLock有两个构造函数:
public ReentrantReadWriteLock() {
this(false);
}
public ReentrantReadWriteLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
readerLock = new ReadLock(this);
writerLock = new WriteLock(this);
}
其中,sync是同步器实例,根据fair参数可以选择公平或非公平模式的同步器。
2. 锁的表示
static final int SHARED_SHIFT = 16;
static final int SHARED_UNIT = (1 << SHARED_SHIFT);
static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1;
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
ReentrantReadWriteLock用一个16位的无符号数来表示锁的占用,其他,前8bit表示读锁,后8bit表示写锁。
/** 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; }
3. 同步器实现
ReentrantReadWriteLock的同步器实现分为两种:公平模式和非公平模式。两种模式的区别在于线程获取锁的顺序不同,公平模式下线程按照请求的顺序获取锁,非公平模式下线程可以插队获取锁。
NonfairSync是非公平模式下的同步器实现。
static final class NonfairSync extends Sync {
private static final long serialVersionUID = -2694183684443567898L;
final void writerAcquire(int arg) {
if (compareAndSetState(0, arg))
exclusiveOwnerThread = Thread.currentThread();
else
acquireQueued(addWaiter(Node.EXCLUSIVE), arg);
}
final boolean tryWriterAcquire(int arg) {
if (getState() != 0)
return false;
if (compareAndSetState(0, arg)) {
exclusiveOwnerThread = Thread.currentThread();
return true;
}
return false;
}
final boolean tryWriterRelease() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
exclusiveOwnerThread = null;
setState(0);
return true;
}
final boolean tryReaderAcquire() {
for (;;) {
int c = getState();
if (exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() != Thread.currentThread())
return false;
int nextc = c + SHARED_UNIT;
if (nextc < c)
throw new Error("Maximum lock count exceeded");
if (compareAndSetState(c, nextc))
return true;
}
}
final boolean tryReaderRelease() {
for (;;) {
int c = getState();
int nextc = c - SHARED_UNIT;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
final int getCount() {
return getState();
}
}
FairSync是公平模式下的同步器实现。
static final class FairSync extends Sync {
private static final long serialVersionUID = -2274990926593161451L;
final void writerAcquire(int arg) {
acquireQueued(addWaiter(Node.EXCLUSIVE), arg);
}
final boolean tryWriterAcquire(int arg) {
Thread current = Thread.currentThread();
int c = getState();
if (c != 0) {
int w = exclusiveCount(c);
if (w == 0 || current != getExclusiveOwnerThread())
return false;
if (w + exclusiveCount(arg) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
setState(c + arg);
return true;
}
if (!hasQueuedPredecessors() && compareAndSetState(0, arg)) {
exclusiveOwnerThread = current;
return true;
}
return false;
}
final boolean tryWriterRelease() {
Thread current = Thread.currentThread();
if (getState() == 0)
throw new IllegalMonitorStateException();
if (getExclusiveOwnerThread() != current)
throw new IllegalMonitorStateException();
int nextc = getState() - 1;
boolean free = exclusiveCount(nextc) == 0;
setState(nextc);
if (free)
exclusiveOwnerThread = null;
return free;
}
final boolean tryReaderAcquire() {
Thread current = Thread.currentThread();
for (;;) {
Node last = tail;
Node p = head;
while (p != last) {
if (!isBeforeSplice(p) &&
p.thread != current)
return false;
p = p.next;
}
int c = getState();
int nextc = c + SHARED_UNIT;
if (nextc < c)
throw new Error("Maximum lock count exceeded");
if (compareAndSetState(c, nextc)) {
boolean first = sharedCount(c) == 0;
if (!first)
return true;
if (firstReader == null)
firstReader = current;
else if (firstReader != current)
nodeWaiterCount = FULL_SHUTDOWN;
return true;
}
}
}
final boolean tryReaderRelease() {
Thread current = Thread.currentThread();
for (;;) {
int c = getState();
int nextc = c - SHARED_UNIT;
if (compareAndSetState(c, nextc)) {
if (nextc == 0) {
firstReader = null;
if (nodeWaiterCount == 2)
unparkSuccessor(head);
} else if (firstReader != null && firstReader != current) {
nodeWaiterCount = FULL_SHUTDOWN;
}
return true;
}
}
}
final int getCount() {
return getState();
}
}
4. 读写锁实现
对于ReentrantReadWriteLock来说,最重要的是提供读锁和写锁的方法。下面是读锁和写锁的实现:
public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable {
static final class ReadLock extends Sync implements Lock {
private static final long serialVersionUID = -5992448646407690164L;
ReadLock(ReentrantReadWriteLock lock) {
super(lock);
}
public void lock() {
sync.acquireShared(1);
}
public void lockInterruptibly() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
public boolean tryLock() {
return sync.tryAcquireShared(1) >= 0;
}
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();
}
}
static final class WriteLock extends Sync implements Lock {
private static final long serialVersionUID = -4992448646407690164L;
WriteLock(ReentrantReadWriteLock lock) {
super(lock);
}
public void lock() {
sync.acquire(1);
}
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
public boolean tryLock() {
return sync.tryAcquire(1);
}
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() {
throw new UnsupportedOperationException();
}
}
final Sync sync;
private final ReadLock readerLock;
private final WriteLock writerLock;
public ReentrantReadWriteLock() {
this(false);
}
public ReentrantReadWriteLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
readerLock = new ReadLock(this);
writerLock = new WriteLock(this);
}
public Lock readLock() {
return readerLock;
}
public Lock writeLock() {
return writerLock;
}
}
读锁和写锁分别继承了Sync类,通过调用Sync类的acquireShared、tryAcquireShared、releaseShared等方法实现了读锁和写锁的功能。
总结
ReentrantReadWriteLock是一种读写锁,它允许多个线程同时读取共享资源,但是只允许一个线程进行写入操作。ReentrantReadWriteLock的实现是基于AbstractQueuedSynchronizer(AQS)的同步器实现的,通过AQS的内部状态和线程的协作,ReentrantReadWriteLock实现了对共享资源的读取和写入操作的互斥和排他。在使用ReentrantReadWriteLock时需要注意读多写少的场景,否则可能出现写操作被饥饿。