含義
管程,指的是管理共享變量以及對共享變量的操做過程html
如何解決線程同步問題
管程模型裏,共享變量和對共享變量的操做是被封裝起來的,圖中最外層的框就表明封裝的意思。框的上面只有一個入口,而且在入口旁邊還有一個入口等待隊列。當多個線程同時試圖進入管程內部時,只容許一個線程進入,其餘線程則在入口等待隊列中等待,管程裏還引入了條件變量的概念,並且 每一個條件變量都對應有一個等待隊列。經過條件變量和等待隊列,解決同步問題,想一想notify,wait的原理實現java
管程的組成segmentfault
MESA 模型安全
MESA 管程裏面,T2 通知完 T1 後,T2 仍是會接着執行,T1 並不當即執行(即調用了notify後,wait並後後面的代碼沒有立刻執行,只是進入了waitSet隊列等待鎖的搶奪,此時是阻塞狀態,而是等待notify釋放鎖後,wait纔開始競爭鎖,奪鎖成功後,繼續執行後續代碼),僅僅是從條件變量的等待隊列進到入口等待隊列裏面。
這樣作的好處是 notify() 不用放到代碼的最後,T2 也沒有多餘的阻塞喚醒操做。可是也有 個反作用,就是當 T1 再次執行的時候,可能曾經知足的條件,如今已經不知足了,因此須要以循環方式檢驗條件變量併發
nofity使用的狀況:app
public class TestMain { private static List<String> list = new ArrayList<>(2); public static void main(String[] args) throws InterruptedException { TestMain testMain = new TestMain(); list.add("1"); Thread thread2 = new Thread(() -> testMain.apply("1","2")); Thread thread3 = new Thread(() -> testMain.apply("1","2")); Thread thread4 = new Thread(() -> testMain.free("1","2")); thread2.start(); thread3.start(); TimeUnit.SECONDS.sleep(1); System.out.println("開始執行通知代碼塊"); thread4.start(); } public synchronized void apply(String one, String two) { System.out.println("獲取鎖 進入 apply = " + Thread.currentThread().getName()); while (list.contains(one) || list.contains(two)) { try { System.out.println("開始等待,而且釋放鎖 = " + Thread.currentThread().getName()); wait(); System.out.println("拿到鎖了,進入條件判斷 = " + Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("離開 釋放鎖 = " + Thread.currentThread().getName()); } public synchronized void free(String one ,String two) { list.remove(one); list.remove(two); notifyAll(); System.out.println("通知完成 離開代碼塊 釋放鎖 = " + Thread.currentThread().getName()); } } -- 結果 獲取鎖 進入 apply = Thread-1![在這裏插入圖片描述](https://img-blog.csdnimg.cn/20190716202958253.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3pmYzA4MjY=,size_16,color_FFFFFF,t_70) 開始等待,而且釋放鎖 = Thread-1 獲取鎖 進入 apply = Thread-0 開始等待,而且釋放鎖 = Thread-0 開始執行通知代碼塊 通知完成 離開代碼塊 釋放鎖 = Thread-2 拿到鎖了,進入條件判斷 = Thread-0 離開 釋放鎖 = Thread-0 拿到鎖了,進入條件判斷 = Thread-1 離開 釋放鎖 = Thread-1
如下四點共同發生,就會產生死鎖,因此破壞某一個條件,終止死鎖oop
資源具備互斥性
若是對象頭已經包含了偏向鎖狀態標識,檢測Mark Word裏是否存儲着指向當前線程的偏向鎖若是存在,
則返回,不然 說明存在鎖競爭,須要進行偏向鎖的釋放源碼分析
偏向鎖的釋放,須要等待全局安全點(在這個時間點上沒有正在執行的字節碼),首先暫停擁有偏向鎖的線程,而後檢查持有偏向鎖的線程是否還活着,
若是線程不處於活動狀態,則將對象頭設置成無鎖狀態。
若是線程仍然活着,則會升級爲輕量級鎖,佈局
偏向鎖撤銷之後對象會可能會處於兩種狀態:性能
以上內容來自如下資料的彙總整理:
極客時間java併發專欄
不可不說的Java「鎖」事
synchronized的源碼分析
Synchronized原理分析
深刻分析synchronized的實現原理
synchronized 的鎖膨脹過程