操做系統在面對線程間同步的時候,會支持例如semaphore信號量和mutex互斥量等同步原語,而monitor是在編程語言中被實現的,下面介紹一下java中monitor(監視器/管程:管理共享變量以及對其的操做過程,讓他們支持併發)的實現原理:java
以一個阻塞隊列的實現來舉例:編程
同時,java內置的synchronized關鍵字能夠認爲是MESA模型的簡化版,其只能有一個條件變量,但編譯器會自動添加加鎖與解鎖的代碼。synchronized關鍵字能夠修飾實例方法、類方法以及代碼塊,若是修飾的是代碼塊,須要制定關聯的Object;若是修飾的是實例方法,那麼其關聯的對象其實是this;若是修飾的是類方法,那麼其關聯的對象是this.class。這些關聯的對象就是MESA模型裏的條件變量。數組
JVM基於進入和退出monitor對象來實現同步,同步代碼塊採用添加moniterenter、moniterexit,同步方法使用ACC_SYNCHRONIZED標記符隱式實現。每一個對象都有一個monitor與之關聯,運行到moniterenter時嘗試獲取對應monitor的全部權,獲取成功就將monitor的進入數加1(因此是可重入鎖,也被稱爲重量級鎖),不然就阻塞,擁有monitor的線程運行到moniterexit時進入數減1,爲0時釋放monitor。
java中每一個對象都有一個對象頭,synchronized所用的鎖就是存在對象頭裏的。若是是非數組的對象是8個字節(32位JVM)或者16字節(64位JVM),數組對象還會有一個數組長度(4個字節)。以32位JVM非數組對象爲例:緩存
鎖信息就存在前4個字節的MarkWord中,JVM對synchronized的加鎖過程優化爲:多線程
重量級鎖是悲觀鎖的一種,自旋鎖、輕量級鎖與偏向鎖屬於樂觀鎖。
CAS設計讀取-比較-寫入三個操做,是在CPU指令層面保證其原子性,volatile是保證多線程下的內存可見性,兩者需配合使用。另外還需注意CPU緩存行(一次以32/64字節爲單位從主內存中讀取數據到緩存)包含多個變量所帶來的隱形同步問題:其中一個變量被volatile修飾,致使另一個變量在另外一個CPU核上(另外一個線程)的讀寫也要被強制刷新緩存。併發
管程:併發編程的萬能鑰匙
java 中的鎖 -- 偏向鎖、輕量級鎖、自旋鎖、重量級鎖