NonfairSync ReentrantReadWriteLock
static final class NonfairSync extends Sync {
private static final long serialVersionUID = -8159625535654395037L;
final boolean writerShouldBlock() {
return false; //非公平實現,總是返回false 不會阻塞
}
final boolean readerShouldBlock() {
//隊列的head後面的節點不爲空且爲非共享的就返回true 就阻塞
return apparentlyFirstQueuedIsExclusive();
}
}
FairSync ReentrantReadWriteLock
//查看隊列是否有先驅
static final class FairSync extends Sync {
private static final long serialVersionUID = -2274990926593161451L;
final boolean writerShouldBlock() {
return hasQueuedPredecessors();
}
final boolean readerShouldBlock() {
return hasQueuedPredecessors();
}
}
ReentrantReadWriteLock的同步實現Sync
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 6317671515068378041L;
/*使用一個32位的int類型來表示被佔用的線程數
加鎖的區域被分爲兩部分,低16位代表獨佔鎖的被同一個線程申請的次數
高位代表共享讀鎖佔有的線程數量*/
static final int SHARED_SHIFT = 16;//讀鎖佔用的位數
static final int SHARED_UNIT = (1 << SHARED_SHIFT);增加一個讀鎖相當於增加一個SHARED_UNIT
static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1;//申請讀鎖的最大線程數量 65535
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;//計算寫鎖的具體值時,該值爲15個1,
//計算申請讀鎖的線程數,將c向右移位16就得到高16位的值
static int sharedCount(int c) { return c >>> SHARED_SHIFT; }
//計算申請寫鎖的數量,將c和16個1相與得到低16位
static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
//每個線程有多少讀鎖
static final class HoldCounter {
int count = 0;
// 使用線程id來避免垃圾保留
final long tid = getThreadId(Thread.currentThread());
}
/**
* ThreadLocal subclass. Easiest to explicitly define for sake
* of deserialization mechanics.
*/
static final class ThreadLocalHoldCounter
extends ThreadLocal<HoldCounter> {
public HoldCounter initialValue() {
return new HoldCounter();
}
}
//當前線程的可重入讀鎖的數量,無論什麼時候一個線程的readHolds變成0就釋放鎖
private transient ThreadLocalHoldCounter readHolds;
private transient HoldCounter cachedHoldCounter;
//第一個獲取讀鎖的線程
private transient Thread firstReader = null;
private transient int firstReaderHoldCount;
Sync() {
readHolds = new ThreadLocalHoldCounter();
setState(getState()); // ensures visibility of readHolds
}
abstract boolean readerShouldBlock();
abstract boolean writerShouldBlock();
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 tryAcquire(int acquires) {
/*
* Walkthrough:
* 1.讀鎖的數量非0或者寫鎖的數量非0,並且鎖的擁有者是其他線程,獲取失敗
* 2. 如果鎖的數量飽和大於65535,失敗
* 3.
*/
Thread current = Thread.currentThread();
int c = getState();//
int w = exclusiveCount(c);//申請寫鎖的數量
if (c != 0) {
// (Note: if c != 0 and w == 0 讀鎖數量不爲0,獨佔鎖獲取失敗)
if (w == 0 || current != getExclusiveOwnerThread())//條件1
return false;
if (w + exclusiveCount(acquires) > MAX_COUNT)//條件2
throw new Error("Maximum lock count exceeded");
// 可重入
setState(c + acquires);
return true;
}
//c==0,說明當前沒有鎖
if (writerShouldBlock() ||//這個實現在子類中,根據是否公平區分
!compareAndSetState(c, c + acquires))
return false;
setExclusiveOwnerThread(current);
return true;
}
//體現firstReader和cachedHoldCounter作用,減少調用readHolds的get方法次數
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;
//判斷當前線程是否是cachedHoldCounter,
//不是就調用readHold的get方法獲取
if (rh == null || rh.tid != getThreadId(current))
rh = readHolds.get();//從ThreadLocalMap中獲取當前線程
int count = rh.count;
if (count <= 1) {
readHolds.remove();//ThreadLocalMap中移除當前線程
if (count <= 0)
throw unmatchedUnlockException();
}
--rh.count;//讀鎖數量減一
}
for (;;) {
int c = getState();
int nextc = c - SHARED_UNIT;
if (compareAndSetState(c, nextc))
// 釋放讀鎖並且不會影響到其他讀者
//但是他可能允許等待的寫者運行,如果讀 寫鎖都是空閒的
return nextc == 0;
}
}
protected final int tryAcquireShared(int unused) {
/*
* 1. If write lock held by another thread, fail.如果寫鎖被其他線程佔有,失敗
* 2.
*/
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.獲取當前是否已經被鎖住,如果c!=0 判斷寫鎖的申請數量是否爲0,是則轉2
不是就判斷是否是當前線程佔用寫鎖,不是返回false是則轉2
2.判斷寫鎖的數量是否超過最大值,是則拋出錯誤,不是就轉3
3.cas的設置c失敗則返回false,否則設置當前線程獨佔鎖,返回true
*/
final boolean tryWriteLock() {
Thread current = Thread.currentThread();
int c = getState();
if (c != 0) {
int w = exclusiveCount(c);
if (w == 0 || current != getExclusiveOwnerThread())
return false;
if (w == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
}
if (!compareAndSetState(c, c + 1))
return false;
setExclusiveOwnerThread(current);
return true;
}
/**
1.寫鎖有沒有被佔用,沒有被佔用轉2,被佔用判斷釋放是當前線程佔用
如果是當前線程佔用,轉2,不是返回false
2.判斷讀鎖的最大數量有沒有超過最大數量,有拋出錯誤,沒有就轉3
3.cas設置state更新firstReader firstReaderHoldCount cachedHoldCounter readHolds
*/
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;
}
}
}
final int getCount() { return getState(); }
}
小結:
- 讀鎖是可以多個線程重入的,寫鎖只能是單個線程重入
- 一個擁有寫鎖的線程可以擁有讀鎖,寫鎖降級爲讀鎖
- 同時佔有讀鎖和寫鎖的線程釋放了寫鎖就降爲讀鎖,此時寫操作是無法重入的
如果寫鎖還未完全釋放是可以重入的
- 公平模式下讀寫鎖的順序必須按照AQS的隊列順序進行,非公平模式下要看
head的下一個節點是否是獨佔的