使用鎖可以讓臨界區(qū)的代碼互斥執(zhí)行。鎖是java并發(fā)編程中最重要的同步機制。
鎖還可以讓釋放鎖的線程向獲取同一個鎖的線程發(fā)送消息
-->鎖的釋放和獲取 內存語義
1. 鎖的釋放:當釋放鎖時,JMM會把該線程對應的本地內存中的共享變量刷新到主內存
2. 鎖的獲取:當獲取鎖時,JMM會把線程對應的本地內存置為無效,而從主內存中讀取共享變量
上述共享變量的范圍:實例字段、靜態(tài)字段‘、數(shù)組對象元素
由此可見鎖的釋放與volatile寫具有相同語義,鎖的獲取與volatile讀具有相同語義。
-->鎖的內存語義實現(xiàn)
代碼級別:調用lock()方法獲取鎖;調用unlock()方法釋放鎖(依賴與AQS同步框架)
鎖分為公平鎖和非公平鎖
公平鎖在釋放鎖的最后寫volatile變量state,在獲取鎖時首先讀這個volatile變量。根據(jù)volatile的happens-before規(guī)則,釋放鎖的線程在寫volatile變量之前可見的共享變量,在獲取鎖的線程讀取同一個volatile變量后將立即變得對獲取鎖的線程可見。
(捂臉...別問我為什么沒有非公平鎖的解釋,才疏學淺..看不懂。這個部分也在和實驗室的同學激烈地討論工作時間與通勤時間中度過)
公平鎖與非公平鎖
1. 公平鎖和非公平鎖釋放時,最后都要寫一個volatile變量state
2. 公平鎖獲取時,首先會去讀volatile變量
3. 非公平鎖獲取鎖時,首先會用CAS更新volatile變量,這個操作同時具有volatile讀和寫的內存語義
總結:鎖釋放-獲取的內存語義的實現(xiàn)至少有下面兩種方式:
1. 利用volatile變量的寫-讀所具有的內存語義;
2. 利用CAS所附帶的volatile讀和volatile寫的內存語義。
Concurrent包的實現(xiàn)
java線程之間的通信有下面4種方式:
1. A線程寫volatile變量,隨后線程B讀這個volatile變量。
2. A線程寫volatile變量,隨后B線程用CAS更新這個變量。
3. A線程用CAS更新一個volatile變量,隨后B線程用CAS更新這個變量。
4. A線程用CAS更新一個volatile變量,隨后B線程讀這個volatile變量。
最后補充一下concurrent包的結構:
? ?Lock ? ? ? ? ? 同步器 ? ? ? ? ? ? ? ? ? ? ?阻塞隊列 ? ? ? ? ? ? ? ? ? ? ?Executor ? ? ? ? 并發(fā)容器
? ? ? ? ? AQS ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 非阻塞數(shù)據(jù)結構 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?原子變量類
? ? ? ? ? volatile變量的讀/寫 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? CAS
concurrent包的源代碼實現(xiàn)是一個通用的模式。
首先,聲明共享變量為volatile。
然后,使用CAS的原子條件更新來實現(xiàn)線程之間的同步。
同時,配合以volatile的讀/寫和CAS所具有的volatile讀和寫的內存語義來實現(xiàn)進程間的通信。
AQS,非阻塞數(shù)據(jù)結構和原子變量類(java.util.concurrent.atomic包中的類),這些concurrent包中的基礎類都是使用這種模式來實現(xiàn)的,而concurrent包中的高層類又是依賴于這些基礎類實現(xiàn)