| 網(wǎng)站首頁 | 關(guān)于我們 | 開發(fā)優(yōu)勢 | 產(chǎn)品展示 |
| 合作企業(yè) | 新聞動(dòng)態(tài) | 聯(lián)系我們 | 電話聯(lián)系 |
文章作者:濟(jì)南軟件開發(fā) 時(shí)間:2016年12月20日
概要
Java的JUC(java.util.concurrent)包中的鎖包括"獨(dú)占鎖"和"共享鎖"。在“Java多線程系列--“JUC鎖”02之 互斥鎖ReentrantLock ”中,對(duì)Java的獨(dú)占鎖進(jìn)行了說明。本章對(duì)Java的“共享鎖”進(jìn)行介紹,JUC中的共享鎖有CountDownLatch, CyclicBarrier, Semaphore, ReentrantReadWriteLock等;本章會(huì)以ReentrantReadWriteLock為藍(lán)本對(duì)共享鎖進(jìn)行說明。內(nèi)容包括:
ReadWriteLock 和 ReentrantReadWriteLock介紹
ReadWriteLock 和 ReentrantReadWriteLock函數(shù)列表
參考代碼(基于JDK1.7.0_40)
獲取共享鎖
釋放共享鎖
公平共享鎖和非公平共享鎖
ReentrantReadWriteLock示例
ReadWriteLock 和 ReentrantReadWriteLock介紹
ReadWriteLock,顧名思義,是讀寫鎖。它維護(hù)了一對(duì)相關(guān)的鎖 — — “讀取鎖”和“寫入鎖”,一個(gè)用于讀取操作,另一個(gè)用于寫入操作。
“讀取鎖”用于只讀操作,它是“共享鎖”,能同時(shí)被多個(gè)線程獲取。
“寫入鎖”用于寫入操作,它是“獨(dú)占鎖”,寫入鎖只能被一個(gè)線程鎖獲取。
注意:不能同時(shí)存在讀取鎖和寫入鎖!
ReadWriteLock是一個(gè)接口。ReentrantReadWriteLock是它的實(shí)現(xiàn)類,ReentrantReadWriteLock包括子類ReadLock和WriteLock。
ReadWriteLock 和 ReentrantReadWriteLock函數(shù)列表
ReadWriteLock函數(shù)列表
// 返回用于讀取操作的鎖。
Lock readLock()
// 返回用于寫入操作的鎖。
Lock writeLock()
ReentrantReadWriteLock函數(shù)列表
復(fù)制代碼
// 創(chuàng)建一個(gè)新的 ReentrantReadWriteLock,默認(rèn)是采用“非公平策略”。
ReentrantReadWriteLock()
// 創(chuàng)建一個(gè)新的 ReentrantReadWriteLock,fair是“公平策略”。fair為true,意味著公平策略;否則,意味著非公平策略。
ReentrantReadWriteLock(boolean fair)
// 返回當(dāng)前擁有寫入鎖的線程,如果沒有這樣的線程,則返回 null。
protected Thread getOwner()
// 返回一個(gè) collection,它包含可能正在等待獲取讀取鎖的線程。
protected Collection<Thread> getQueuedReaderThreads()
// 返回一個(gè) collection,它包含可能正在等待獲取讀取或?qū)懭腈i的線程。
protected Collection<Thread> getQueuedThreads()
// 返回一個(gè) collection,它包含可能正在等待獲取寫入鎖的線程。
protected Collection<Thread> getQueuedWriterThreads()
// 返回等待獲取讀取或?qū)懭腈i的線程估計(jì)數(shù)目。
int getQueueLength()
// 查詢當(dāng)前線程在此鎖上保持的重入讀取鎖數(shù)量。
int getReadHoldCount()
// 查詢?yōu)榇随i保持的讀取鎖數(shù)量。
int getReadLockCount()
// 返回一個(gè) collection,它包含可能正在等待與寫入鎖相關(guān)的給定條件的那些線程。
protected Collection<Thread> getWaitingThreads(Condition condition)
// 返回正等待與寫入鎖相關(guān)的給定條件的線程估計(jì)數(shù)目。
int getWaitQueueLength(Condition condition)
// 查詢當(dāng)前線程在此鎖上保持的重入寫入鎖數(shù)量。
int getWriteHoldCount()
// 查詢是否給定線程正在等待獲取讀取或?qū)懭腈i。
boolean hasQueuedThread(Thread thread)
// 查詢是否所有的線程正在等待獲取讀取或?qū)懭腈i。
boolean hasQueuedThreads()
// 查詢是否有些線程正在等待與寫入鎖有關(guān)的給定條件。
boolean hasWaiters(Condition condition)
// 如果此鎖將公平性設(shè)置為 ture,則返回 true。
boolean isFair()
// 查詢是否某個(gè)線程保持了寫入鎖。
boolean isWriteLocked()
// 查詢當(dāng)前線程是否保持了寫入鎖。
boolean isWriteLockedByCurrentThread()
// 返回用于讀取操作的鎖。
ReentrantReadWriteLock.ReadLock readLock()
// 返回用于寫入操作的鎖。
ReentrantReadWriteLock.WriteLock writeLock()
復(fù)制代碼
參考代碼(基于JDK1.7.0_40)
ReentrantReadWriteLock的完整源碼
View Code
AQS的完整源碼
View Code
其中,共享鎖源碼相關(guān)的代碼如下:
復(fù)制代碼
public static class ReadLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = -5992448646407690164L;
// ReentrantReadWriteLock的AQS對(duì)象
private final Sync sync;
protected ReadLock(ReentrantReadWriteLock lock) {
sync = lock.sync;
}
// 獲取“共享鎖”
public void lock() {
sync.acquireShared(1);
}
// 如果線程是中斷狀態(tài),則拋出一場,否則嘗試獲取共享鎖。
public void lockInterruptibly() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
// 嘗試獲取“共享鎖”
public boolean tryLock() {
return sync.tryReadLock();
}
// 在指定時(shí)間內(nèi),嘗試獲取“共享鎖”
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();
}
public String toString() {
int r = sync.getReadLockCount();
return super.toString() +
"[Read locks = " + r + "]";
}
}
復(fù)制代碼
說明:
ReadLock中的sync是一個(gè)Sync對(duì)象,Sync繼承于AQS類,即Sync就是一個(gè)鎖。ReentrantReadWriteLock中也有一個(gè)Sync對(duì)象,而且ReadLock中的sync和ReentrantReadWriteLock中的sync是對(duì)應(yīng)關(guān)系。即ReentrantReadWriteLock和ReadLock共享同一個(gè)AQS對(duì)象,共享同一把鎖。
ReentrantReadWriteLock中Sync的定義如下:
final Sync sync;
下面,分別從“獲取共享鎖”和“釋放共享鎖”兩個(gè)方面對(duì)共享鎖進(jìn)行說明。
獲取共享鎖
獲取共享鎖的思想(即lock函數(shù)的步驟),是先通過tryAcquireShared()嘗試獲取共享鎖。嘗試成功的話,則直接返回;嘗試失敗的話,則通過doAcquireShared()不斷的循環(huán)并嘗試獲取鎖,若有需要,則阻塞等待。doAcquireShared()在循環(huán)中每次嘗試獲取鎖時(shí),都是通過tryAcquireShared()來進(jìn)行嘗試的。下面看看“獲取共享鎖”的詳細(xì)流程。
1. lock()
lock()在ReadLock中,源碼如下:
public void lock() {
sync.acquireShared(1);
}
2. acquireShared()
Sync繼承于AQS,acquireShared()定義在AQS中。源碼如下:
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
說明:acquireShared()首先會(huì)通過tryAcquireShared()來嘗試獲取鎖。
嘗試成功的話,則不再做任何動(dòng)作(因?yàn)橐呀?jīng)成功獲取到鎖了)。
嘗試失敗的話,則通過doAcquireShared()來獲取鎖。doAcquireShared()會(huì)獲取到鎖了才返回。
3. tryAcquireShared()
tryAcquireShared()定義在ReentrantReadWriteLock.java的Sync中,源碼如下:
復(fù)制代碼
protected final int tryAcquireShared(int unused) {
Thread current = Thread.currentThread();
// 獲取“鎖”的狀態(tài)
int c = getState();
// 如果“鎖”是“互斥鎖”,并且獲取鎖的線程不是current線程;則返回-1。
if (exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() != current)
return -1;
// 獲取“讀取鎖”的共享計(jì)數(shù)
int r = sharedCount(c);
// 如果“不需要阻塞等待”,并且“讀取鎖”的共享計(jì)數(shù)小于MAX_COUNT;
// 則通過CAS函數(shù)更新“鎖的狀態(tài)”,將“讀取鎖”的共享計(jì)數(shù)+1。
if (!readerShouldBlock() &&
r < MAX_COUNT &&
compareAndSetState(c, c + SHARED_UNIT)) {
// 第1次獲取“讀取鎖”。
if (r == 0) {
firstReader = current;
firstReaderHoldCount = 1;
// 如果想要獲取鎖的線程(current)是第1個(gè)獲取鎖(firstReader)的線程
} else if (firstReader == current) {
firstReaderHoldCount++;
} else {
// HoldCounter是用來統(tǒng)計(jì)該線程獲取“讀取鎖”的次數(shù)。
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != current.getId())
cachedHoldCounter = rh = readHolds.get();
else if (rh.count == 0)
readHolds.set(rh);
// 將該線程獲取“讀取鎖”的次數(shù)+1。
rh.count++;
}
return 1;
}
return fullTryAcquireShared(current);
}
復(fù)制代碼
說明:tryAcquireShared()的作用是嘗試獲取“共享鎖”。
如果在嘗試獲取鎖時(shí),“不需要阻塞等待”并且“讀取鎖的共享計(jì)數(shù)小于MAX_COUNT”,則直接通過CAS函數(shù)更新“讀取鎖的共享計(jì)數(shù)”,以及將“當(dāng)前線程獲取讀取鎖的次數(shù)+1”。
否則,通過fullTryAcquireShared()獲取讀取鎖。
4. fullTryAcquireShared()
fullTryAcquireShared()在ReentrantReadWriteLock中定義,源碼如下:
復(fù)制代碼
final int fullTryAcquireShared(Thread current) {
HoldCounter rh = null;
for (;;) {
// 獲取“鎖”的狀態(tài)
int c = getState();
// 如果“鎖”是“互斥鎖”,并且獲取鎖的線程不是current線程;則返回-1。
if (exclusiveCount(c) != 0) {
if (getExclusiveOwnerThread() != current)
return -1;
// 如果“需要阻塞等待”。
// (01) 當(dāng)“需要阻塞等待”的線程是第1個(gè)獲取鎖的線程的話,則繼續(xù)往下執(zhí)行。
// (02) 當(dāng)“需要阻塞等待”的線程獲取鎖的次數(shù)=0時(shí),則返回-1。
} else if (readerShouldBlock()) {
// 如果想要獲取鎖的線程(current)是第1個(gè)獲取鎖(firstReader)的線程
if (firstReader == current) {
} else {
if (rh == null) {
rh = cachedHoldCounter;
if (rh == null || rh.tid != current.getId()) {
rh = readHolds.get();
if (rh.count == 0)
readHolds.remove();
}
}
// 如果當(dāng)前線程獲取鎖的計(jì)數(shù)=0,則返回-1。
if (rh.count == 0)
return -1;
}
}
// 如果“不需要阻塞等待”,則獲取“讀取鎖”的共享統(tǒng)計(jì)數(shù);
// 如果共享統(tǒng)計(jì)數(shù)超過MAX_COUNT,則拋出異常。
if (sharedCount(c) == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// 將線程獲取“讀取鎖”的次數(shù)+1。
if (compareAndSetState(c, c + SHARED_UNIT)) {
// 如果是第1次獲取“讀取鎖”,則更新firstReader和firstReaderHoldCount。
if (sharedCount(c) == 0) {
firstReader = current;
firstReaderHoldCount = 1;
// 如果想要獲取鎖的線程(current)是第1個(gè)獲取鎖(firstReader)的線程,
// 則將firstReaderHoldCount+1。
} else if (firstReader == current) {
firstReaderHoldCount++;
} else {
if (rh == null)
rh = cachedHoldCounter;
if (rh == null || rh.tid != current.getId())
rh = readHolds.get();
else if (rh.count == 0)
readHolds.set(rh);
// 更新線程的獲取“讀取鎖”的共享計(jì)數(shù)
rh.count++;
cachedHoldCounter = rh; // cache for release
}
return 1;
}
}
}
復(fù)制代碼
說明:fullTryAcquireShared()會(huì)根據(jù)“是否需要阻塞等待”,“讀取鎖的共享計(jì)數(shù)是否超過限制”等等進(jìn)行處理。如果不需要阻塞等待,并且鎖的共享計(jì)數(shù)沒有超過限制,則通過CAS嘗試獲取鎖,并返回1。
5. doAcquireShared()
doAcquireShared()定義在AQS函數(shù)中,源碼如下:
復(fù)制代碼
private void doAcquireShared(int arg) {
// addWaiter(Node.SHARED)的作用是,創(chuàng)建“當(dāng)前線程”對(duì)應(yīng)的節(jié)點(diǎn),并將該線程添加到CLH隊(duì)列中。
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
// 獲取“node”的前一節(jié)點(diǎn)
final Node p = node.predecessor();
// 如果“當(dāng)前線程”是CLH隊(duì)列的表頭,則嘗試獲取共享鎖。
if (p == head) {
int r = tryAcquireShared(arg);
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
if (interrupted)
selfInterrupt();
failed = false;
return;
}
}
// 如果“當(dāng)前線程”不是CLH隊(duì)列的表頭,則通過shouldParkAfterFailedAcquire()判斷是否需要等待,
// 需要的話,則通過parkAndCheckInterrupt()進(jìn)行阻塞等待。若阻塞等待過程中,線程被中斷過,則設(shè)置interrupted為true。
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
復(fù)制代碼
說明:doAcquireShared()的作用是獲取共享鎖。
它會(huì)首先創(chuàng)建線程對(duì)應(yīng)的CLH隊(duì)列的節(jié)點(diǎn),然后將該節(jié)點(diǎn)添加到CLH隊(duì)列中。CLH隊(duì)列是管理獲取鎖的等待線程的隊(duì)列。
如果“當(dāng)前線程”是CLH隊(duì)列的表頭,則嘗試獲取共享鎖;否則,則需要通過shouldParkAfterFailedAcquire()判斷是否阻塞等待,需要的話,則通過parkAndCheckInterrupt()進(jìn)行阻塞等待。
doAcquireShared()會(huì)通過for循環(huán),不斷的進(jìn)行上面的操作;目的就是獲取共享鎖。需要注意的是:doAcquireShared()在每一次嘗試獲取鎖時(shí),是通過tryAcquireShared()來執(zhí)行的!
若讀者對(duì)CLH隊(duì)列,shouldParkAfterFailedAcquire(), parkAndCheckInterrupt()等內(nèi)容的細(xì)節(jié)感興趣,可以參考“Java多線程系列--“JUC鎖”02之 互斥鎖ReentrantLock”。
釋放共享鎖
釋放共享鎖的思想,是先通過tryReleaseShared()嘗試釋放共享鎖。嘗試成功的話,則通過doReleaseShared()喚醒“其他等待獲取共享鎖的線程”,并返回true;否則的話,返回flase。
1. unlock()
public void unlock() {
sync.releaseShared(1);
}
說明:該函數(shù)實(shí)際上調(diào)用releaseShared(1)釋放共享鎖。
2. releaseShared()
releaseShared()在AQS中實(shí)現(xiàn),源碼如下:
復(fù)制代碼
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
復(fù)制代碼
說明:releaseShared()的目的是讓當(dāng)前線程釋放它所持有的共享鎖。
它首先會(huì)通過tryReleaseShared()去嘗試釋放共享鎖。嘗試成功,則直接返回;嘗試失敗,則通過doReleaseShared()去釋放共享鎖。
3. tryReleaseShared()
tryReleaseShared()定義在ReentrantReadWriteLock中,源碼如下:
復(fù)制代碼
protected final boolean tryReleaseShared(int unused) {
// 獲取當(dāng)前線程,即釋放共享鎖的線程。
Thread current = Thread.currentThread();
// 如果想要釋放鎖的線程(current)是第1個(gè)獲取鎖(firstReader)的線程,
// 并且“第1個(gè)獲取鎖的線程獲取鎖的次數(shù)”=1,則設(shè)置firstReader為null;
// 否則,將“第1個(gè)獲取鎖的線程的獲取次數(shù)”-1。
if (firstReader == current) {
// assert firstReaderHoldCount > 0;
if (firstReaderHoldCount == 1)
firstReader = null;
else
firstReaderHoldCount--;
// 獲取rh對(duì)象,并更新“當(dāng)前線程獲取鎖的信息”。
} else {
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != current.getId())
rh = readHolds.get();
int count = rh.count;
if (count <= 1) {
readHolds.remove();
if (count <= 0)
throw unmatchedUnlockException();
}
--rh.count;
}
for (;;) {
// 獲取鎖的狀態(tài)
int c = getState();
// 將鎖的獲取次數(shù)-1。
int nextc = c - SHARED_UNIT;
// 通過CAS更新鎖的狀態(tài)。
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
復(fù)制代碼
說明:tryReleaseShared()的作用是嘗試釋放共享鎖。
4. doReleaseShared()
doReleaseShared()定義在AQS中,源碼如下:
復(fù)制代碼
private void doReleaseShared() {
for (;;) {
// 獲取CLH隊(duì)列的頭節(jié)點(diǎn)
Node h = head;
// 如果頭節(jié)點(diǎn)不為null,并且頭節(jié)點(diǎn)不等于tail節(jié)點(diǎn)。
if (h != null && h != tail) {
// 獲取頭節(jié)點(diǎn)對(duì)應(yīng)的線程的狀態(tài)
int ws = h.waitStatus;
// 如果頭節(jié)點(diǎn)對(duì)應(yīng)的線程是SIGNAL狀態(tài),則意味著“頭節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)所對(duì)應(yīng)的線程”需要被unpark喚醒。
if (ws == Node.SIGNAL) {
// 設(shè)置“頭節(jié)點(diǎn)對(duì)應(yīng)的線程狀態(tài)”為空狀態(tài)。失敗的話,則繼續(xù)循環(huán)。
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue;
// 喚醒“頭節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)所對(duì)應(yīng)的線程”。
unparkSuccessor(h);
}
// 如果頭節(jié)點(diǎn)對(duì)應(yīng)的線程是空狀態(tài),則設(shè)置“文件點(diǎn)對(duì)應(yīng)的線程所擁有的共享鎖”為其它線程獲取鎖的空狀態(tài)。
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue; // loop on failed CAS
}
// 如果頭節(jié)點(diǎn)發(fā)生變化,則繼續(xù)循環(huán)。否則,退出循環(huán)。
if (h == head) // loop if head changed
break;
}
}
復(fù)制代碼
說明:doReleaseShared()會(huì)釋放“共享鎖”。它會(huì)從前往后的遍歷CLH隊(duì)列,依次“喚醒”然后“執(zhí)行”隊(duì)列中每個(gè)節(jié)點(diǎn)對(duì)應(yīng)的線程;最終的目的是讓這些線程釋放它們所持有的鎖。
公平共享鎖和非公平共享鎖
和互斥鎖ReentrantLock一樣,ReadLock也分為公平鎖和非公平鎖。
公平鎖和非公平鎖的區(qū)別,體現(xiàn)在判斷是否需要阻塞的函數(shù)readerShouldBlock()是不同的。
公平鎖的readerShouldBlock()的源碼如下:
final boolean readerShouldBlock() {
return hasQueuedPredecessors();
}
在公平共享鎖中,如果在當(dāng)前線程的前面有其他線程在等待獲取共享鎖,則返回true;否則,返回false。
非公平鎖的readerShouldBlock()的源碼如下:
final boolean readerShouldBlock() {
return apparentlyFirstQueuedIsExclusive();
}
在非公平共享鎖中,它會(huì)無視當(dāng)前線程的前面是否有其他線程在等待獲取共享鎖。只要該非公平共享鎖對(duì)應(yīng)的線程不為null,則返回true。
ReentrantReadWriteLock示例
復(fù)制代碼
1 import java.util.concurrent.locks.ReadWriteLock;
2 import java.util.concurrent.locks.ReentrantReadWriteLock;
3
4 public class ReadWriteLockTest1 {
5
6 public static void main(String[] args) {
7 // 創(chuàng)建賬戶
8 MyCount myCount = new MyCount("4238920615242830", 10000);
9 // 創(chuàng)建用戶,并指定賬戶
10 User user = new User("Tommy", myCount);
11
12 // 分別啟動(dòng)3個(gè)“讀取賬戶金錢”的線程 和 3個(gè)“設(shè)置賬戶金錢”的線程
13 for (int i=0; i<3; i++) {
14 user.getCash();
15 user.setCash((i+1)*1000);
16 }
17 }
18 }
19
20 class User {
21 private String name; //用戶名
22 private MyCount myCount; //所要操作的賬戶
23 private ReadWriteLock myLock; //執(zhí)行操作所需的鎖對(duì)象
24
25 User(String name, MyCount myCount) {
26 this.name = name;
27 this.myCount = myCount;
28 this.myLock = new ReentrantReadWriteLock();
29 }
30
31 public void getCash() {
32 new Thread() {
33 public void run() {
34 myLock.readLock().lock();
35 try {
36 System.out.println(Thread.currentThread().getName() +" getCash start");
37 myCount.getCash();
38 Thread.sleep(1);
39 System.out.println(Thread.currentThread().getName() +" getCash end");
40 } catch (InterruptedException e) {
41 } finally {
42 myLock.readLock().unlock();
43 }
44 }
45 }.start();
46 }
47
48 public void setCash(final int cash) {
49 new Thread() {
50 public void run() {
51 myLock.writeLock().lock();
52 try {
53 System.out.println(Thread.currentThread().getName() +" setCash start");
54 myCount.setCash(cash);
55 Thread.sleep(1);
56 System.out.println(Thread.currentThread().getName() +" setCash end");
57 } catch (InterruptedException e) {
58 } finally {
59 myLock.writeLock().unlock();
60 }
61 }
62 }.start();
63 }
64 }
65
66 class MyCount {
67 private String id; //賬號(hào)
68 private int cash; //賬戶余額
69
70 MyCount(String id, int cash) {
71 this.id = id;
72 this.cash = cash;
73 }
74
75 public String getId() {
76 return id;
77 }
78
79 public void setId(String id) {
80 this.id = id;
81 }
82
83 public int getCash() {
84 System.out.println(Thread.currentThread().getName() +" getCash cash="+ cash);
85 return cash;
86 }
87
88 public void setCash(int cash) {
89 System.out.println(Thread.currentThread().getName() +" setCash cash="+ cash);
90 this.cash = cash;
91 }
92 }
復(fù)制代碼
運(yùn)行結(jié)果:
復(fù)制代碼
Thread-0 getCash start
Thread-2 getCash start
Thread-0 getCash cash=10000
Thread-2 getCash cash=10000
Thread-0 getCash end
Thread-2 getCash end
Thread-1 setCash start
Thread-1 setCash cash=1000
Thread-1 setCash end
Thread-3 setCash start
Thread-3 setCash cash=2000
Thread-3 setCash end
Thread-4 getCash start
Thread-4 getCash cash=2000
Thread-4 getCash end
Thread-5 setCash start
Thread-5 setCash cash=3000
Thread-5 setCash end
復(fù)制代碼
結(jié)果說明:
(01) 觀察Thread0和Thread-2的運(yùn)行結(jié)果,我們發(fā)現(xiàn),Thread-0啟動(dòng)并獲取到“讀取鎖”,在它還沒運(yùn)行完畢的時(shí)候,Thread-2也啟動(dòng)了并且也成功獲取到“讀取鎖”。
因此,“讀取鎖”支持被多個(gè)線程同時(shí)獲取。
(02) 觀察Thread-1,Thread-3,Thread-5這三個(gè)“寫入鎖”的線程。只要“寫入鎖”被某線程獲取,則該線程運(yùn)行完畢了,才釋放該鎖。
因此,“寫入鎖”不支持被多個(gè)線程同時(shí)獲取。
想要了解更多詳情歡迎來電咨詢18678812288
登陸網(wǎng)址:m.h6244.cn。
聯(lián)系人:王經(jīng)理。