在說volatile的內存語義時,講過這樣一句話:想要理解透volatile特性有一個很好的方法,就是把對volatile變量的單個讀/寫,當作是使用同一個鎖對這些單個讀/寫操做作了同步。因此其實鎖的釋放和獲取與volatile的寫和讀具備相同的內存語義。html
不清楚happens-before規則的請前去看-看,這裏就不在細說了。因爲在以前沒有舉例說明監視器鎖規則,那麼在這裏就詳細說明下,下面是鎖釋放-獲取的示例代碼:併發
public class MonitorExample { int a = 0; public synchronized void writer() { // 1 a += 1; // 2 } // 3 public synchronized void reader() { // 4 System.out.println(a); // 5 } // 6 public static void main(String[] args) { final MonitorExample me = new MonitorExample(); Thread t1 = new Thread(new Runnable() { @Override public void run() { me.writer(); } }); t1.start(); Thread t2 = new Thread(new Runnable() { @Override public void run() { me.reader(); } }); t2.start(); } }
這裏咱們假設線程1先執行writer()方法,隨後線程B執行reader()方法(知道爲何要假設?由於不是必定按這種順序發生,能夠測試下結果)。根據happens-before規則,這個過程包含的happens-before關係能夠分爲3類:app
1) 根據程序次序規則:1 happens-before 2, 2 happens-before 3, 4 happens-before 5, 5 happens-before 6;ide
2)根據監視器鎖規則:3 happens-before 4;測試
3)根據傳遞性規則,2 happens-before 5。spa
上述happens-before關係的圖形化表現形式以下:線程
當線程釋放鎖時,JMM會把該線程對應的本地內存中的共享變量刷新到主內存中。以上面的MonitorExample程序爲例,線程1釋放鎖後,共享數據的狀態示意圖以下:code
當線程獲取鎖時,JMM會把該線程對應的本地內存置爲無效。從而使得被監視器保護的臨界區代碼必須從主內存中讀取共享變量。htm
對比鎖釋放-讀取的內存語義與volatile寫-讀的內存語義能夠看出,鎖釋放與volatile寫具備相同的內存語義;鎖獲取與volatile讀具備相同的內存語義。下面對鎖釋放和鎖獲取的內存語義作個總結。blog
鎖有不少種,但其基本原理都是差很少的。書上是以ReentrantLock中的公平鎖與非公平鎖做爲案例分析,有興趣的同窗能夠去閱讀原籍和源碼。現總結以下:
因此鎖釋放-獲取的內存語義的實現至少有下面兩種方式:
1)利用volatile變量的寫-讀所具備的內存語義。
2)利用CAS所附帶的volatile讀和volatile寫的內存語義。
由此可知:併發包下的類的實現方式大部分都是基於這兩種方式實現的。