前言
本文將分析讀寫鎖
ReentrantReadWriteLock
的源碼,也會在分析中穿插一些例子來加深對源碼的理解. 本文會如以下順序介紹.
1. 整體架構(gòu)
2. 讀寫狀態(tài)的設(shè)計
3. 寫鎖的源碼分析并以例子加深理解
4. 讀鎖的源碼分析并以例子加深理解
5. 鎖降級
本文源碼下載
整體架構(gòu)
讀寫鎖在讀線程獲得鎖時可以允許多個讀線程同時訪問,但是在寫線程獲得鎖時,所有的讀線程和其他寫線程均被阻塞.
從上圖可以看到
1.
ReentrantReadWriteLock
主要是實現(xiàn)了接口ReadWriteLock
來實現(xiàn)讀寫鎖,并且真正返回的讀鎖是ReadLock
的一個實例,寫鎖是WriteLock
的一個實例.
2.ReentrantReadWriteLock
中有一個Sync
的成員變量sync
(Sync
是ReentrantReadWriteLock
內(nèi)部類), 并且ReadLock
和WriteLock
使用了該成員變量sync
來實現(xiàn)它們從接口Lock
繼承的抽象方法.
3.Sync
的一個實例sync
可以是一個FairSync
或者NonfairSync
, 并且Sync
類繼承了AbstractQueuedSynchronizer
,由此可知Sync
是ReentrantReadWriteLock
類的核心,并且實現(xiàn)了讀寫鎖的具體邏輯.
接下來分析的內(nèi)容都是跟
Sync
類息息相關(guān).
讀寫狀態(tài)的設(shè)計
先了解一下讀寫狀態(tài)的設(shè)計. 我們知道
AQS
中有一個狀態(tài)值, 比如在ReentrantLock
中表示持有鎖的線程重入了多少次. 但是在ReentrantReadWriteLock
中有讀鎖和寫鎖因此需要劃分,所以高16
位代表讀鎖的狀態(tài),低16
位代表寫鎖的狀態(tài).
如圖所示,一個線程已經(jīng)獲取了寫鎖,并且重進(jìn)入了兩次,同時也連續(xù)獲取了兩次讀鎖.(有人可能會疑惑為什么在獲得寫鎖的同時還可以獲得讀鎖呢, 在鎖降級的時候你會得到答案.)
從讀寫鎖的作用可知讀鎖是一個共享鎖, 寫鎖是一個互斥鎖. 因此
sharedCount(int c)
是為了獲取讀鎖的狀態(tài)值,exclusiveCount(int c)
是為了獲取寫鎖的狀態(tài)值.
abstract static class Sync extends AbstractQueuedSynchronizer {
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;
/** 返回c的高16位 讀狀態(tài)*/
static int sharedCount(int c) { return c >>> SHARED_SHIFT; }
/** 返回c的低16位 寫狀態(tài)*/
static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
}
寫鎖的獲取和釋放
先分析寫鎖是因為寫鎖與之前分析的鎖在獲取和釋放的過程基本類似,而讀鎖相較于寫鎖會稍微復(fù)雜一點點.
寫鎖的獲取
源碼如下
作用: 當(dāng)前線程嘗試獲取寫鎖, 獲取成功返回true
,獲取失敗返回false
.
/**
* 作用: 寫鎖的獲取
*
* @param acquires 獲取的個數(shù)
* @return true表示獲取鎖, false表示未獲取鎖
*/
protected final boolean tryAcquire(int acquires) {
Thread current = Thread.currentThread();
int c = getState(); // 整體狀態(tài)
int w = exclusiveCount(c); // 寫狀態(tài)的個數(shù)
/**
* 整體狀態(tài)如果等于0 表明讀鎖和寫鎖目前都沒有線程獲取到 則可以去獲取寫鎖
* 如果不等于0
* 1. 存在讀鎖或者當(dāng)前線程不是已經(jīng)獲取寫鎖的線程,則直接返回
* 2. 如果寫鎖的數(shù)量沒有超過最高值則獲得寫鎖
*/
if (c != 0) {
// (Note: if c != 0 and w == 0 then shared count != 0)
// 存在讀鎖或者當(dāng)前線程不是已經(jīng)獲取寫鎖的線程
if (w == 0 || current != getExclusiveOwnerThread())
return false;
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// 重入式獲取
setState(c + acquires);
return true;
}
/**
* 表示整體狀態(tài)為0
* 如果writeShouldBlock需要阻塞或者CAS操作不成功則返回false
*/
if (writerShouldBlock() ||
!compareAndSetState(c, c + acquires))
return false;
/**
* 請注意setExclusiveOwnerThread該方法設(shè)置的是寫鎖
*/
setExclusiveOwnerThread(current); // 設(shè)置當(dāng)前線程是獲得寫鎖的線程
return true;
}
其實獲取寫鎖的邏輯比較簡單. 具體細(xì)節(jié)可以參考上面的注解.
1. 如果不存在讀鎖或?qū)戞i(狀態(tài)為0
),則成功獲取鎖并設(shè)置setExclusiveOwnerThread
后返回true
.
2. 如果存在讀鎖,則直接返回false
.
3. 如果存在寫鎖, 分以下兩種情況:
- 3.1 如果寫鎖的線程不是當(dāng)前線程,則返回
false
.- 3.2 如果寫鎖的重入數(shù)已經(jīng)超過了最大值,則返回
false
.- 3.3 設(shè)置寫鎖的重入數(shù)(加
1
), 返回true
.
流程圖如下:
關(guān)于writeShouldBlock()
和readShouldBlock()
這兩個方法是
Sync
的抽象方法, 由子類實現(xiàn), 可以看一下公平鎖和非公平鎖的具體實現(xiàn).
static final class NonfairSync extends Sync {
private static final long serialVersionUID = -8159625535654395037L;
// 寫鎖永遠(yuǎn)不需要阻塞
final boolean writerShouldBlock() {
return false; // writers can always barge
}
final boolean readerShouldBlock() {
/* As a heuristic to avoid indefinite writer starvation,
* block if the thread that momentarily appears to be head
* of queue, if one exists, is a waiting writer. This is
* only a probabilistic effect since a new reader will not
* block if there is a waiting writer behind other enabled
* readers that have not yet drained from the queue.
*/
return apparentlyFirstQueuedIsExclusive();
}
}
static final class FairSync extends Sync {
private static final long serialVersionUID = -2274990926593161451L;
final boolean writerShouldBlock() {
return hasQueuedPredecessors();
}
final boolean readerShouldBlock() {
return hasQueuedPredecessors();
}
// 如果前面有節(jié)點 返回true 說明需要阻塞
}
寫鎖的釋放
作用: 寫鎖的釋放
/**
*
* 作用: 寫鎖的釋放
* @param releases 釋放的個數(shù)
* @return 寫鎖是否完全釋放 true 完全釋放
*/
protected final boolean tryRelease(int releases) {
// 如果當(dāng)前線程不是已經(jīng)獲取寫鎖的線程,則直接拋出異常
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
int nextc = getState() - releases;
boolean free = exclusiveCount(nextc) == 0;
// 判斷寫鎖(重入鎖)是否已經(jīng)全部釋放完
if (free)
setExclusiveOwnerThread(null);
setState(nextc); // 設(shè)置狀態(tài)
return free;
}
例子: 測試寫鎖的獲取和釋放
工具類
SleepUnit
和Cache
package com.sourcecode.reentrantreadwritelock;
import java.util.HashMap;
import java.util.Map;
public class Cache {
static Map<String, Object> map = new HashMap<String, Object>();
static ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
static Lock r = rwl.readLock();
static Lock w = rwl.writeLock();
// 獲取一個key對應(yīng)的value
public static final Object get(String key) {
r.lock();
try {
System.out.println(Thread.currentThread().getName() + " gets lock.");
SleepUnit.sleep(5);
return map.get(key);
} finally {
System.out.println(Thread.currentThread().getName() + " releases lock.");
r.unlock();
}
}
// 設(shè)置key對應(yīng)的value刺洒,并返回舊的value
public static final Object put(String key, Object value) {
w.lock();
try {
System.out.println(Thread.currentThread().getName() + " gets lock.");
SleepUnit.sleep(10);
return map.put(key, value);
} finally {
System.out.println(Thread.currentThread().getName() + " releases lock.");
w.unlock();
}
}
// 清空所有的內(nèi)容
public static final void clear() {
w.lock();
try {
map.clear();
} finally {
w.unlock();
}
}
}
public class SleepUnit {
public static void sleep(int time) {
try {
TimeUnit.SECONDS.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
測試類. 啟動五個線程去獲取寫鎖,通過打印出
AQS
中的等待隊列來觀察情況.
public class TestCache {
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
new Thread(new Runner(), "thread-" + i).start();
}
for (int i = 0; i < 10; i++) {
SleepUnit.sleep(5);
Cache.rwl.printWaitingNode();
}
}
static class Runner implements Runnable {
public void run() {
Cache.put("k0", "k0");
}
}
}
結(jié)果輸出: 結(jié)果并沒有什么意外, 當(dāng)所有線程嘗試去獲取寫鎖時只有一個線程可以拿到鎖.
thread-0 gets lock.
[NULL,-1]->[thread-3,獨占,-1]->[thread-2,獨占,-1]->[thread-1,獨占,-1]->[thread-4,獨占,0]->
[NULL,-1]->[thread-3,獨占,-1]->[thread-2,獨占,-1]->[thread-1,獨占,-1]->[thread-4,獨占,0]->
thread-3 gets lock.
[NULL,-1]->[thread-2,獨占,-1]->[thread-1,獨占,-1]->[thread-4,獨占,0]->
[NULL,0]->thread-2 gets lock.
[thread-2,獨占,-1]->[thread-1,獨占,-1]->[thread-4,獨占,0]->
[NULL,-1]->[thread-1,獨占,-1]->[thread-4,獨占,0]->
thread-1 gets lock.
[NULL,-1]->[thread-4,獨占,0]->
[NULL,-1]->[thread-4,獨占,0]->
thread-4 gets lock.
[NULL,0]->
[NULL,0]->
[NULL,0]->
讀鎖的獲取和釋放
讀鎖相對于寫鎖來說比較復(fù)雜點,因為讀鎖的時候是共享的,意味著每個線程都可以獲得線程, 又因為讀鎖是可重入的,所以每個獲得讀鎖的線程都有一個對應(yīng)的可重入的數(shù)量.說到這里很容易就會想到用
ThreadLocal
類來實現(xiàn)的. 關(guān)于ThreadLocal
可以參考我的另外一篇博客[Java源碼][并發(fā)J.U.C]---解析ThreadLocal, 因此接下來先介紹一下讀鎖用到的一些變量及其作用.
讀鎖使用到的變量介紹
/**
* 一個ThreadLocal的子類,value值是HoldCounter類的對象并重寫了initValue()方法
*/
static final class ThreadLocalHoldCounter
extends ThreadLocal<HoldCounter> {
public HoldCounter initialValue() {
return new HoldCounter();
}
}
/**
* 一個thredlocal實例保存線程對應(yīng)的HoldCount
* 在構(gòu)造函數(shù)或者readObject中完成初始化
* 當(dāng)讀鎖線程的重入數(shù)變?yōu)?時,會被removed.
*/
private transient ThreadLocalHoldCounter readHolds;
/**
* 成功獲取讀鎖的最后一個線程的HoldCounter對象.
* 為了避免總是去readHolds中查找
*/
private transient HoldCounter cachedHoldCounter;
/**
* firstReader是第一個獲得讀鎖定的線程,
* 嚴(yán)格意義上是第一個使得讀鎖狀態(tài)值從0變?yōu)?的線程
* firstReaderHoldCount是其對應(yīng)的重入數(shù)
*
*/
private transient Thread firstReader = null;
private transient int firstReaderHoldCount;
/**
* 構(gòu)造函數(shù), 初始化readHolds并設(shè)置狀態(tài)
*/
Sync() {
readHolds = new ThreadLocalHoldCounter();
setState(getState()); // ensures visibility of readHolds
}
在讀鎖中主要使用了三個變量來保持讀鎖的獲取和釋放.
1.firstReader
存儲著第一個把整體狀態(tài)從0
變?yōu)?code>1的線程.
2.cachedHoldCounter
保存著最后一個獲取讀鎖線程的HoldCounter
對象.
3.readHolds
保存每個線程和其對應(yīng)的HoldCounter
對象, 不包括firstReader
, 包括最后一個獲取讀鎖線程.
讀鎖的獲取
tryAcquireShared
方法.
/**
* @param unused 釋放
* @return 返回一個數(shù)值如果大于等于0,表明獲得鎖.
* 返回一個數(shù)值如果小于0,表明沒有獲得鎖.
*/
protected final int tryAcquireShared(int unused) {
Thread current = Thread.currentThread();
int c = getState(); //獲取當(dāng)前狀態(tài)
if (exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() != current) //如果寫鎖存在并且寫鎖持有者不是當(dāng)前線程
return -1;
// 說明 1.寫鎖不存在 或者 2.寫鎖存在但是寫鎖持有者是當(dāng)前線程
int r = sharedCount(c); // 獲取讀鎖的個數(shù)
/**
* 1. 讀鎖不需要阻塞.
* 2. 讀鎖的總個數(shù)沒有超過最大數(shù).
* 3. 通過CAS設(shè)置c的狀態(tài) 因為高16位是讀鎖的個數(shù) 所以需要加上1<<16.
*/
if (!readerShouldBlock() &&
r < MAX_COUNT &&
compareAndSetState(c, c + SHARED_UNIT)) {
/**
* 上面三個條件都滿足的情況下會進(jìn)入這里繼續(xù)執(zhí)行
* 1. r == 0 意味著當(dāng)前線程是第一個獲得讀鎖的線程(之前沒有獲得過).
* 2. firstReader == current 意味當(dāng)前線程是那個之前第一個獲得讀鎖的線程 可以重入
* 3. 如果都不是就說明當(dāng)前線程不是第一個獲得讀鎖的線程,因此當(dāng)前線程最起碼是第二個獲得讀鎖的線程,
* a. 先去cachedHoldCounter看一下是不是最后一次獲得讀鎖的線程,如果不是就把當(dāng)前線程緩存起來
* (因為此時該線程是目前最后一個獲得讀鎖的線程)
* b. 如果是的話如果rh.count==0,就需要把從readHolds中添加進(jìn)去
* (這是因為在對應(yīng)的release中rh.count==0的時候readHolds做了清除操作)
* rh.count++
* 返回1,代表成功獲得鎖.
*/
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);
}
作用: 嘗試獲取讀鎖, 返回大于等于
0
的數(shù)表明獲得鎖, 返回小于0
的數(shù)表明未獲得鎖.
邏輯如下:
1. 如果另一個線程持有寫鎖定,則失敗.
2. 如果進(jìn)入到這里表明兩種情況寫鎖不存在或者寫鎖存在但是寫鎖持有者就是當(dāng)前線程
3. 如果同時滿足3個條件分別是a.讀鎖不需要阻塞和b.讀鎖的總個數(shù)沒有超過最大數(shù)和c.CAS設(shè)置狀態(tài)成功, 則當(dāng)前線程成功獲得讀鎖. 否則進(jìn)入fullTryAcquireShared
方法(放到后面分析).
4. 滿足了上面3
個條件后需要更新讀鎖的相關(guān)變量.基本邏輯如下:
- 4.1 如果讀鎖狀態(tài)值為
0
,表明該線程是第一個獲得讀鎖的線程,設(shè)置firstReader
和firstReadHoldCount
變量.- 4.2 如果不是4.1則表明讀鎖已經(jīng)被線程獲取過了,那么如果當(dāng)前線程就是那個第一次獲得讀鎖的線程,則設(shè)置其重入數(shù)
firstReaderHoldCount
即可.- 4.3 如果不是4.2則表明讀鎖已經(jīng)被獲取過了并且當(dāng)前線程并不是那個第一次獲得讀鎖的線程,此時就可以去緩存
cachedHoldCounter
中看看是不是當(dāng)前線程,如果不是的話就從readHolds
中獲取并將其緩存在cachedHoldCounter
中. 最后rh.count++
設(shè)置一下重入數(shù).
注意 當(dāng)某個HoldCounter
的count
為0的時候,readHolds
是會將其清除掉的.
流程圖如下:
fullTryAcquireShared
方法
/**
* 作用: 獲取鎖, 返回值大于等于0表示
* 用于處理tryAcquireShared方法中未能滿足的3個條件
*/
final int fullTryAcquireShared(Thread current) {
HoldCounter rh = null;
for (;;) {
int c = getState(); // 獲取當(dāng)前狀態(tài)
if (exclusiveCount(c) != 0) { // 如果寫鎖不為0 表明存在寫鎖
// 如果寫鎖不是當(dāng)前線程(說明此刻已經(jīng)有別的線程獲得寫鎖了),則需要阻塞當(dāng)前線程所以返回-1.
if (getExclusiveOwnerThread() != current)
return -1;
// else we hold the exclusive lock; blocking here
// would cause deadlock.
/**
* 這一段話的意思是如果當(dāng)前線程如果在這里block了,那會形成死鎖,
* 因為當(dāng)前線程已經(jīng)在持有寫鎖的情況來請求讀鎖的,那么該鎖在沒有釋放鎖的情況下block了
* 就會形成死鎖了
*/
} else if (readerShouldBlock()) { // 不存在寫鎖并且需要阻塞
// Make sure we're not acquiring read lock reentrantly
/**
* 確認(rèn)一下當(dāng)前線程有沒有在之前獲得鎖,也就是在阻塞前確認(rèn)一下不是重入讀鎖的線程
* 如果是重入鎖的話就讓他操作CAS 如果不是的話就需要阻塞
* 至于為什么,我個人理解如下:
* 對公平鎖來說,readShouldBlock()返回true,表明AQS隊列中有等待寫鎖的線程,
* 那么如果重入讀鎖也返回-1讓其阻塞的話那就會形成死鎖,因為該重入讀鎖由于阻塞無法釋放讀鎖躲叼,
* AQS等待隊列中的寫鎖又因為讀鎖的存在而無法獲得寫鎖從而形成死鎖了.
*/
if (firstReader == current) { // 當(dāng)前線程已經(jīng)獲得過鎖則
// assert firstReaderHoldCount > 0;
} else {
if (rh == null) {
rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current)) {
rh = readHolds.get();
if (rh.count == 0) // 計數(shù)為0, 需要從readHolds中刪除
readHolds.remove();
}
}
if (rh.count == 0) //說明當(dāng)前線程之前沒有獲得鎖
return -1;
}
}
// 如果讀鎖的個數(shù)達(dá)到最大值拋出error
if (sharedCount(c) == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// CAS操作 邏輯跟tryAcquireShared方法里面的類似.
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;
}
}
}
fullTryAcquireShared
是為了處理tryAcquireShared
中無法同時滿足那三個條件而進(jìn)行的處理方法,for
循環(huán)操作.
1. 如果存在寫鎖并且寫鎖不是當(dāng)前線程則需要阻塞當(dāng)前線程返回-1.
2. 如果存在寫鎖并且寫鎖就是當(dāng)前線程則不需要管readerShouldBlock()
方法進(jìn)行CAS
操作.
3. 如果不存在寫鎖,如果當(dāng)前線程之前獲得過讀鎖則進(jìn)行CAS
操作,否則返回-1,阻塞當(dāng)前線程.
4. 如果讀鎖的個數(shù)達(dá)到最大值則拋出Error
.
5. 進(jìn)行CAS
操作.
對于第3點的個人理解
對公平鎖來說,readShouldBlock()返回true,表明AQS隊列中有等待寫鎖的線程,那么如果重入讀鎖也返回-1讓其阻塞的話那就會形成死鎖,因為該重入讀鎖由于阻塞無法釋放讀鎖,AQS等待隊列中的寫鎖又因為讀鎖的存在而無法獲得寫鎖從而形成死鎖了.
對應(yīng)流程圖如下:
讀鎖的釋放
/**
* 作用: 釋放讀鎖
* @param unused
* @return
*/
protected final boolean tryReleaseShared(int unused) {
Thread current = Thread.currentThread(); // 獲取當(dāng)前線程
/**
* 1. firstReader == current 表明當(dāng)前線程是那個第一個獲得讀鎖的線程,可以直接操作firstReaderHolderCount就可以了
* 2. 如果不是則看是不是最后一次獲得讀鎖的線程,
* a. 如果不是則取出當(dāng)前線程對應(yīng)的holdcount,保存到rh中
* b. 如果是直接保存到rh
*
* 如果rh的count為1,表明當(dāng)前線程獲得讀鎖后沒有重入過,既然是釋放鎖,這個時候就需要從threadlocal中刪除掉
*
* rh.count--
*
*/
if (firstReader == current) {
// assert firstReaderHoldCount > 0;
if (firstReaderHoldCount == 1)
firstReader = null;
else
firstReaderHoldCount--;
} else {
HoldCounter rh = cachedHoldCounter;
// 不是最后一個獲得讀鎖的線程,需要從threadlocal中也就是readHolds中取出當(dāng)前線程的HoldCount
if (rh == null || rh.tid != getThreadId(current))
rh = readHolds.get();
int count = rh.count;
// count <= 1 需要從readHolds中刪除, 進(jìn)一步如果count<=0表明錯誤
if (count <= 1) {
readHolds.remove();
if (count <= 0)
throw unmatchedUnlockException();
}
// 無論怎么樣 rh已經(jīng)是當(dāng)前線程對應(yīng)的HoldCount, 釋放一個就是減少一個
--rh.count;
}
// 循環(huán)操作更新狀態(tài), 如果讀鎖的個數(shù)為0,則表明所有讀鎖都釋放完畢這個時候返回true.
// 不然其他情況都是返回false.
for (;;) {
int c = getState();
int nextc = c - SHARED_UNIT;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
作用: 釋放讀鎖,返回true如果所有的讀鎖釋放完,否則返回false.
邏輯很簡單,可以直接看代碼注解.
鎖降級
鎖降級: 鎖降級指的是寫鎖降級成為讀鎖凿蒜。如果當(dāng)前線程擁有寫鎖,然后將其釋放,最后再獲取讀鎖,這種分段完成的過程不能稱之為鎖降級.鎖降級是指把持住(當(dāng)前擁有的)寫鎖,再獲取到讀鎖,隨后釋放(先前擁有的)寫鎖的過程.
其實讀鎖這部分已經(jīng)分析到了鎖降級的內(nèi)容了, 在上面的分析中我們已經(jīng)看到在當(dāng)前線程獲取讀鎖的過程中如果存在寫鎖并且該寫鎖就是當(dāng)前線程的時候可以去獲得讀鎖.
必要性: 主要是為了保證數(shù)據(jù)的可見性,如果當(dāng)前線程不獲取讀鎖而是直接釋放寫鎖(接著不加鎖直接讀取數(shù)據(jù)),假設(shè)此刻另一個線程(記作線程T)獲取了寫鎖并修改了數(shù)據(jù),那么當(dāng)前線程無法感知線程T的數(shù)據(jù)更新. 如果當(dāng)前線程獲取讀鎖,即遵循鎖降級的步驟,則線程T將會被阻塞,直到當(dāng)前線程使用數(shù)據(jù)并釋放讀鎖之后,線程T才能獲取寫鎖進(jìn)行數(shù)據(jù)更新。
Sync
類中一些其余的方法
/**
* 嘗試獲取寫鎖,該方法給tryLock調(diào)用,返回false該線程也不會阻塞
*/
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;
}
/**
* 嘗試獲取讀鎖,該方法給tryLock調(diào)用,返回false該線程也不會阻塞
*/
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;
}
}
}
ReadLock 和 WriteLock
代碼就不貼了,因為都是調(diào)用的
Sync
類的方法.
參考
1. Java并發(fā)編程的藝術(shù)
2. http://www.reibang.com/p/6923c126e762
3. http://www.reibang.com/p/f81925c8835a