ReentrantReadWriteLock读写锁是基于AQS的独占模式和共享模式实现的,是为了优化ReentrantLock互斥锁的并发性能;
个人主页:tuzhenyu’s page
原文地址:Java多线程系列(十一)—ReentrantReadWriteLock源码分析
class ReadThread extends Thread{
private ReentrantReadWriteLock lock;
public ReadThread(String name,ReentrantReadWriteLock lock){
super(name);
this.lock = lock;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" try to lock");
lock.readLock().lock();
System.out.println(Thread.currentThread().getName()+" lock successfully");
try {
sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
lock.readLock().unlock();
System.out.println(Thread.currentThread().getName()+" unlock successfully");
}
}
class WriteThread extends Thread{
private ReentrantReadWriteLock lock;
public WriteThread(String name,ReentrantReadWriteLock lock){
super(name);
this.lock = lock;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" try to lock");
lock.writeLock().lock();
System.out.println(Thread.currentThread().getName()+" lock successfully");
try {
sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
lock.writeLock().unlock();
System.out.println(Thread.currentThread().getName()+" unlock successfully");
}
}
public class ReentrantReadWriteLockDemo {
public static void main(String[] args) {
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
ReadThread r1 = new ReadThread("r1",lock);
ReadThread r2 = new ReadThread("r2",lock);
WriteThread w1 = new WriteThread("w1",lock);
WriteThread w2 = new WriteThread("w2",lock);
r1.start();
r2.start();
w1.start();
w2.start();
}
}
运行结果
r1 try to lock
r1 lock successfully
r2 try to lock
r2 lock successfully
w1 try to lock
w2 try to lock
r1 unlock successfully
r2 unlock successfully
w1 lock successfully
w1 unlock successfully
w2 lock successfully
w2 unlock successfully
private final ReentrantReadWriteLock.ReadLock readerLock;
private final ReentrantReadWriteLock.WriteLock writerLock;
final Sync sync;
// 返回用于读取操作的锁。
ReentrantReadWriteLock.ReadLock readLock()
// 返回用于写入操作的锁。 ReentrantReadWriteLock.WriteLock writeLock()
ReentrantReadWriteLock有五个内部类,五个内部类之间也是相互关联的.
Sync类内存在两个内部类,分别为HoldCounter和ThreadLocalCounter;
// 计数器
static final class HoldCounter {
// 计数
int count = 0;
// 获取当前线程的TID属性的值
final long tid = getThreadId(Thread.currentThread());
}
// 本地线程计数器
static final class ThreadLocalHoldCounter
extends ThreadLocal<HoldCounter> {
// 重写初始化方法,在没有进行set的情况下,获取的都是该HoldCounter值
public HoldCounter initialValue() {
return new HoldCounter();
}
}
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; }
public void lock() {
sync.acquireShared(1);
}
public void unlock() {
sync.releaseShared(1);
}
public void lock() {
sync.acquire(1);
}
public void unlock() {
sync.release(1);
}
static int sharedCount(int c) { return c >>> SHARED_SHIFT; }
static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
public void lock() {
sync.acquire(1);
}
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
tryAcquire()方法尝试获取写锁
首先获取state值和写锁数量,如果state为0则表示没有线程占用读写锁,则判断公平模式和非公平模式是否获取该锁;如果state不为0则表示存在读锁或者写锁;
如果state不为0,判断写锁数目是否为0和当前线程是否已经独占该锁,如果当前线程已经独占该锁,则修改state的写锁重入次数;
protected final boolean tryAcquire(int acquires) {
Thread current = Thread.currentThread();
int c = getState();
int w = exclusiveCount(c);
if (c != 0) {
// (Note: if c != 0 and w == 0 then shared count != 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;
}
非公平锁
final boolean writerShouldBlock() {
return false; // writers can always barge
}
公平锁
final boolean writerShouldBlock() {
return hasQueuedPredecessors();
}
public void unlock() {
sync.release(1);
}
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
tryRelease()方法释放写锁
调用isHeldExclusively()方法判断当前线程是否为独占,写锁拥有的线程肯定是独占,如果不是则抛出异常;
修改state的值释放写锁
protected final boolean tryRelease(int releases) {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
int nextc = getState() - releases;
boolean free = exclusiveCount(nextc) == 0;
if (free)
setExclusiveOwnerThread(null);
setState(nextc);
return free;
}
protected final boolean isHeldExclusively() {
return getExclusiveOwnerThread() == Thread.currentThread();
}
public void lock() {
sync.acquireShared(1);
}
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
protected final int tryAcquireShared(int unused) {
Thread current = Thread.currentThread();
// 获取“锁”的状态
int c = getState();
// 如果“锁”是“互斥锁”,并且获取锁的线程不是current线程;则返回-1。
//如果当前锁是写锁,则共享锁被阻塞;
if (exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() != current)
return -1;
// 获取“读取锁”的共享计数
int r = sharedCount(c);
// 如果“不需要阻塞等待”,并且“读取锁”的共享计数小于MAX_COUNT;
// 则通过CAS函数更新“锁的状态”,将“读取锁”的共享计数+1。
if (!readerShouldBlock() &&
r < MAX_COUNT &&
compareAndSetState(c, c + SHARED_UNIT)) {
// 第1次获取“读取锁”。
if (r == 0) {
firstReader = current;
firstReaderHoldCount = 1;
// 如果想要获取锁的线程(current)是第1个获取锁(firstReader)的线程
} else if (firstReader == current) {
firstReaderHoldCount++;
} else {
// HoldCounter是用来统计该线程获取“读取锁”的次数。
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != current.getId())
cachedHoldCounter = rh = readHolds.get();
else if (rh.count == 0)
readHolds.set(rh);
// 将该线程获取“读取锁”的次数+1。
rh.count++;
}
return 1;
}
return fullTryAcquireShared(current);
}
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 we hold the exclusive lock; blocking here
// would cause deadlock.
} else if (readerShouldBlock()) {
// Make sure we're not acquiring read lock reentrantly
if (firstReader == current) {
// assert firstReaderHoldCount > 0;
} 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)
return -1;
}
}
if (sharedCount(c) == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
if (compareAndSetState(c, c + SHARED_UNIT)) {
if (sharedCount(c) == 0) {
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) {
firstReaderHoldCount++;
} else {
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;
}
}
}
public void unlock() {
sync.releaseShared(1);
}
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
protected final boolean tryReleaseShared(int unused) {
Thread current = Thread.currentThread();
if (firstReader == current) {
// assert firstReaderHoldCount > 0;
if (firstReaderHoldCount == 1)
firstReader = null;
else
firstReaderHoldCount--;
} else {
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;
if (compareAndSetState(c, nextc){
return nextc == 0;
}
}
private void doReleaseShared() {
for (;;) {
Node h = head;
if (h != null && h != tail) {
int ws = h.waitStatus;
if (ws == Node.SIGNAL) {
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue; // loop to recheck cases
unparkSuccessor(h);
}
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue; // loop on failed CAS
}
if (h == head) // loop if head changed
break;
}
}