揭秘JUC:volatile與CAS,并發(fā)編程的兩大基石
JUC(java.util.concurrent)并發(fā)包,作為Java語言并發(fā)編程的利器,由并發(fā)編程領(lǐng)域的泰斗道格·利(Doug Lea)精心打造。它提供了一系列高效、線程安全的工具類、接口及原子類,極大地簡化了并發(fā)編程的開發(fā)流程與管理復(fù)雜度。
JUC并發(fā)包與happens-before、內(nèi)存語義的關(guān)系

探索JUC并發(fā)包,會(huì)發(fā)現(xiàn)它與Java內(nèi)存模型中的happens-before原則及內(nèi)存語義緊密相連。從高層視角俯瞰,volatile關(guān)鍵字與CAS(Compare-And-Swap)操作構(gòu)成了JUC并發(fā)包底層實(shí)現(xiàn)的核心基石。接下來,以并發(fā)工具Lock為例,剖析其背后的實(shí)現(xiàn)機(jī)制。
class LockExample {
int x = 0;
Lock lock = new ReentrantLock();
public void set() {
// 獲取鎖
lock.lock();
try {
x = 1;
} finally {
// 釋放鎖
lock.unlock();
}
}
public void get() {
// 獲取鎖
lock.lock();
try {
int i = x;
// ......
} finally {
// 釋放鎖
lock.unlock();
}
}
}
Lock的實(shí)現(xiàn)依賴于Java同步器框架(AbstractQueuedSynchronizer,AQS)。AQS內(nèi)部維護(hù)了一個(gè)由volatile修飾的整型變量state,用于表示同步狀態(tài)。
? 1)獲取鎖?:當(dāng)調(diào)用Lock的lock()方法時(shí),會(huì)觸發(fā)AQS的tryAcquire()方法嘗試獲取鎖。該方法首先檢查當(dāng)前state是否為0(表示鎖未被占用),若是,則通過CAS操作將state設(shè)置為1,并標(biāo)記當(dāng)前線程為鎖的持有者。若鎖已被當(dāng)前線程持有(即重入鎖情況),則直接增加state的值。
? 2)釋放鎖?:當(dāng)調(diào)用Lock的unlock()方法時(shí),會(huì)觸發(fā)AQS的tryRelease()方法釋放鎖。該方法首先減少state的值,若減少后state為0,則表示鎖已完全釋放,同時(shí)清除鎖的持有者信息。
// 關(guān)鍵volatile變量
private volatile int state;
protected final boolean tryAcquire(int acquires) {
// 1 獲取到當(dāng)前線程
final Thread current = Thread.currentThread();
// 2 獲取到當(dāng)前鎖的state值
int c = getState();
// 3 如果state值為0,則是無線程占用鎖
if (c == 0) {
// 4 compareAndSetState則通過CAS對(duì)state進(jìn)行設(shè)置為1
if (compareAndSetState(0, acquires)) {
// 5 設(shè)置占用線程為當(dāng)前線程并返回true
setExclusiveOwnerThread(current);
return true;
}
}
// 6 如果state不為0,并且當(dāng)前線程等于鎖占用的線程,則說明鎖重入了。
else if (current == getExclusiveOwnerThread()) {
// 7 直接將state設(shè)置為+1
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
// 8 如果是false,則說明是其他線程,直接返回false。
return false;
}
protected final boolean tryRelease(int releases) {
// 1 對(duì)state進(jìn)行減值
int c = getState() - releases;
// 2 判斷當(dāng)前線程等于鎖占用的線程
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
// 3 當(dāng)c值為0,代表釋放鎖成功
if (c == 0) {
free = true;
// 4 設(shè)置為當(dāng)前鎖沒有線程獨(dú)占
setExclusiveOwnerThread(null);
}
// 5 將state重新置為0,意味其他線程可以重新?lián)屾i
setState(c);
// 6 釋放鎖成功
return free;
}
從上述代碼中,可以觀察到volatile變量state在鎖獲取與釋放過程中的關(guān)鍵作用。根據(jù)volatile的happens-before規(guī)則,釋放鎖的線程在修改volatile變量之前對(duì)共享變量的修改,對(duì)于后續(xù)獲取該鎖的線程來說是可見的。這確保了鎖機(jī)制的正確性與線程間的數(shù)據(jù)一致性。
為了更直觀地理解Lock的獲取與釋放過程,我們可以將其簡化為如下偽代碼。
class SimplifiedLockExample {
int x = 0;
volatile int state;
public void set() {
// 當(dāng)前線程從主內(nèi)存讀取state值
while(state != 0) {
// 偽代碼 阻塞當(dāng)前線程
park(Thread.currentThread())
}
// CAS操作,確保只有一個(gè)線程能成功設(shè)置state為1
compareAndSwap(state, 1)
// 賦值操作,受volatile內(nèi)存語義保護(hù),防止重排序
x = 1;
// 釋放鎖,將state重置為0
state = 0;
// 喚醒其他等待線程
unpark(nonCurrentThread());
}
public void get() {
// 當(dāng)前線程從主內(nèi)存讀取state值
while(state != 0) {
// 阻塞當(dāng)前線程,等待鎖釋放
park(Thread.currentThread())
}
// CAS操作,嘗試獲取鎖
compareAndSwap(state, 1)
// 讀取共享變量x的最新值
int i = x;
// 其他操作...
// 釋放鎖,將state重置為0
state = 0;
// 喚醒其他等待線程
unpark(nonCurrentThread());
}
// 偽代碼方法,實(shí)際實(shí)現(xiàn)需依賴底層系統(tǒng)調(diào)用
private void park(Thread thread)
private void unpark(Thread thread)
private boolean compareAndSwap(int expect, int newValue, int updateValue)
private Thread nonCurrentThread()
}
Java的CAS會(huì)使用現(xiàn)代處理器上提供的原子指令,實(shí)現(xiàn)無鎖的線程安全更新機(jī)制。同時(shí),volatile變量的讀/寫可以實(shí)現(xiàn)線程線程之間的通信。如果仔細(xì)分析JUC并發(fā)包的源代碼實(shí)現(xiàn),會(huì)發(fā)現(xiàn)一個(gè)通用化的實(shí)現(xiàn)模式。
? 1)聲明共享變量為volatile?:確保變量的可見性與有序性。
? 2)使用CAS的原子條件更新?:實(shí)現(xiàn)線程間的同步與數(shù)據(jù)的一致性更新。
? 3)配合volatile的讀/寫內(nèi)存語義?:實(shí)現(xiàn)線程間的通信與數(shù)據(jù)傳遞。
這一模式在AQS、非阻塞數(shù)據(jù)結(jié)構(gòu)(如ConcurrentHashMap)及原子變量類(如AtomicInteger)等JUC并發(fā)包的基礎(chǔ)類中得到了廣泛應(yīng)用。而這些基礎(chǔ)類又進(jìn)一步支撐了JUC并發(fā)包中高層類的實(shí)現(xiàn),構(gòu)建了一個(gè)層次分明、功能強(qiáng)大的并發(fā)編程框架。
未完待續(xù)
很高興與你相遇!如果你喜歡本文內(nèi)容,記得關(guān)注哦
本文來自博客園,作者:poemyang,轉(zhuǎn)載請(qǐng)注明原文鏈接:http://www.rzrgm.cn/poemyang/p/19114881
posted on 2025-09-27 11:28 poemyang 閱讀(218) 評(píng)論(0) 收藏 舉報(bào)
浙公網(wǎng)安備 33010602011771號(hào)