談談 java線程同步機制--標準答案

一 java線程同步原理

java中的同步使用到了 Monitor(管程)機制
java會為每個object對象分配一個monitor晃危,當某個對象的同步方法(synchronized methods)被多個線程調用時,該對象的monitor將負責處理這些訪問的并發(fā)獨占要求震叮。

當一個線程調用一個對象的同步方法時,JVM會檢查該對象的monitor朴则。如果monitor沒有被占用钓简,那么這個線程就得到了monitor的占有權外邓,可以繼續(xù)執(zhí)行該對象的同步方法;如果monitor被其他線程所占用侦啸,那么該線程將被掛起丧枪,直到monitor被釋放。
當線程退出同步方法調用時忘闻,該線程會釋放monitor齐佳,這將允許其他等待的線程獲得monitor以使對同步方法的調用執(zhí)行下去债沮。

注意:Java對象的monitor機制和傳統(tǒng)的臨界檢查代碼區(qū)技術不一樣。java的一個同步方法并不意味著同時只有一個線程獨占執(zhí)行硅蹦,但臨界檢查代碼區(qū)技術確實會保證同步方法在一個時刻只被一個線程獨占執(zhí)行。Java的monitor機制的準確含義是:任何時刻海雪,對一個指定object對象的某同步方法只能由一個線程來調用饲宛。

java對象的monitor是跟隨object實例來使用的,而不是跟隨程序代碼幕庐。兩個線程可以同時執(zhí)行相同的同步方法,比如:一個類的同步方法是xMethod()瑟由,有a,b兩個對象實例冤寿,一個線程執(zhí)行a.xMethod()督怜,另一個線程執(zhí)行b.xMethod().互不沖突。

二 synchronized 和 volatile 号杠、ReentrantLock 的區(qū)別

Synchronized和volatile的比較

? 1)Synchronized保證內存可見性和操作的原子性姨蟋,Volatile只能保證內存可見性。
? 2)volatile不需要加鎖神得,比Synchronized更輕量級哩簿,并不會阻塞線程(volatile不會造成線程的阻塞酝静;synchronized可能會造成線程的阻塞。)
? 4)volatile標記的變量不會被編譯器優(yōu)化,而synchronized標記的變量可以被編譯器優(yōu)化(如編譯器重排序的優(yōu)化).
? 5)volatile是變量修飾符宗苍,僅能用于變量讳窟,而synchronized是一個方法或塊的修飾符敞恋。

ReentrantLock 和 Synchronized

1、可重入性:
2补箍、鎖的實現(xiàn):
3坑雅、性能的區(qū)別:
4、功能區(qū)別:
5终蒂、鎖的細粒度和靈活度

1遥诉、可重入性:
從名字上理解突那,ReenTrantLock的字面意思就是再進入的鎖,其實synchronized關鍵字所使用的鎖也是可重入的早龟,兩者關于這個的區(qū)別不大猫缭。兩者都是同一個線程沒進入一次猜丹,鎖的計數器都自增1,所以要等到鎖的計數器下降為0時才能釋放鎖藏杖。
2脉顿、鎖的實現(xiàn):
Synchronized是依賴于JVM實現(xiàn)的艾疟,而ReenTrantLock是JDK實現(xiàn)的,有什么區(qū)別弟疆,說白了就類似于操作系統(tǒng)來控制實現(xiàn)和用戶自己敲代碼實現(xiàn)的區(qū)別盗冷。前者的實現(xiàn)是比較難見到的正塌,后者有直接的源碼可供閱讀。
3帜羊、性能的區(qū)別:
在Synchronized優(yōu)化以前鸠天,synchronized的性能是比ReenTrantLock差很多的稠集,但是自從Synchronized引入了偏向鎖,輕量級鎖(自旋鎖)后痹籍,兩者的性能就差不多了晦鞋,在兩種方法都可用的情況下悠垛,官方甚至建議使用synchronized,其實synchronized的優(yōu)化我感覺就借鑒了ReenTrantLock中的CAS技術斤讥。都是試圖在用戶態(tài)就把加鎖問題解決湾趾,避免進入內核態(tài)的線程阻塞搀缠。
4、功能區(qū)別:
便利性:很明顯Synchronized的使用比較方便簡潔蛉艾,并且由編譯器去保證鎖的加鎖和釋放勿侯,而ReenTrantLock需要手工聲明來加鎖和釋放鎖缴罗,為了避免忘記手工釋放鎖造成死鎖,所以最好在finally中聲明釋放鎖兵钮。
5掘譬、鎖的細粒度和靈活度:很明顯ReenTrantLock優(yōu)于Synchronized

ReenTrantLock獨有的能力:

1、ReenTrantLock可以指定是公平鎖還是非公平鎖睦焕。而synchronized只能是非公平鎖靴拱。所謂的公平鎖就是先等待的線程先獲得鎖袜炕。
2、ReenTrantLock提供了一個Condition(條件)類耕突,用來實現(xiàn)分組喚醒需要喚醒的線程們眷茁,而不是像synchronized要么隨機喚醒一個線程要么喚醒全部線程纵诞。
3浙芙、ReenTrantLock提供了一種能夠中斷等待鎖的線程的機制,通過lock.lockInterruptibly()來實現(xiàn)這個機制纸俭。
ReenTrantLock實現(xiàn)的原理:

在網上看到相關的源碼分析南窗,本來這塊應該是本文的核心万伤,但是感覺比較復雜就不一一詳解了,簡單來說简珠,ReenTrantLock的實現(xiàn)是一種自旋鎖虹钮,通過循環(huán)調用CAS操作來實現(xiàn)加鎖。它的性能比較好也是因為避免了使線程進入內核態(tài)的阻塞狀態(tài)氧映。想盡辦法避免線程進入內核的阻塞狀態(tài)是我們去分析和理解鎖設計的關鍵鑰匙攘宙。

什么情況下使用ReenTrantLock:
答案是蹭劈,如果你需要實現(xiàn)ReenTrantLock的三個獨有功能時线召。

三 悲觀鎖樂觀鎖

悲觀鎖
總是假設最壞的情況缓淹,每次去拿數據的時候都認為別人會修改, 每次都加鎖
共享資源每次只給一個線程使用,其它線程阻塞料仗,用完后再把資源轉讓給其它線程
Java中synchronized和ReentrantLock等獨占鎖就是悲觀鎖思想的實現(xiàn)立轧。

樂觀鎖
假設最好的情況躏吊,每次去拿數據的時候都認為別人不會修改比伏,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個數據葛躏,可以使用版本號機制和CAS算法實現(xiàn)悠菜。樂觀鎖適用于多讀的應用類型李剖,這樣可以提高吞吐量

兩種鎖的使用場景
樂觀鎖適用于多讀少寫,即沖突真的很少發(fā)生的時候偶芍,這樣可以省去了鎖的開銷,加大了系統(tǒng)的整個吞吐量椎麦。
悲觀鎖適用于多寫少讀的情況观挎,一般會經常產生沖突段化,這就會導致上層應用會不斷的進行retry显熏,這樣反倒是降低了性能

樂觀鎖常見的兩種實現(xiàn)方式

CAS 和 版本號管理,
AtomicReference類計語CAS實現(xiàn), 但會有 ABA 的問題, AtomicStampedReference 同時有cas 和版本號管理的實現(xiàn)

樂觀鎖(CAS)的思想是不加鎖,那不加鎖如何確保某一變量的操作沒有被其他線程修改過缓升?
這里就需要CAS操作(CompareAndSwap)來實現(xiàn)港谊。
CAS有三個操作參數:內存地址橙弱,期望值膘螟,要修改的新值,當期望值和內存當中的值進行比較不相等的時候奴艾,表示內存中的值已經被別線程改動過内斯,這時候失敗返回俘闯,只有相等時,才會將內存中的值改為新的值此疹,并返回成功。

public final long getAndIncrement() {
   return unsafe.getAndAddLong(this, valueOffset, 1L);
}
public final long getAndAddLong(Object var1, long var2, long var4) {
   long var6;
   do {
       var6 = this.getLongVolatile(var1, var2);
   } while(!this.compareAndSwapLong(var1, var2, var6, var6 + var4));
   return var6;
}

可以看到AtomicLong.getAndIncrement()的實現(xiàn)就是通過CAS循環(huán)操作的實現(xiàn)湖笨,只有期望值與真實值相同情況下慈省,CAS操作才會成功執(zhí)行眠菇,退出循環(huán)捎废,如果失敗則繼續(xù)自旋缕坎,直到成功篡悟。

ABA問題

ABA問題是指在CAS操作時搬葬,其他線程將變量值A改為了B,但是又被改回了A急凰,等到本線程使用期望值A與當前變量進行比較時女仰,發(fā)現(xiàn)變量A沒有變,于是CAS就將A值進行了交換操作抡锈,但是實際上該值已經被其他線程改變過疾忍,這與樂觀鎖的設計思想不符合。ABA問題的解決思路是床三,每次變量更新的時候把變量的版本號加1一罩,那么A-B-A就會變成A1-B2-A3撇簿,只要變量被某一線程修改過聂渊,改變量對應的版本號就會發(fā)生遞增變化,從而解決了ABA問題四瘫。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末汉嗽,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子找蜜,更是在濱河造成了極大的恐慌饼暑,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異弓叛,居然都是意外死亡迈着,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進店門邪码,熙熙樓的掌柜王于貴愁眉苦臉地迎上來裕菠,“玉大人,你說我怎么就攤上這事闭专∨耍” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵影钉,是天一觀的道長画髓。 經常有香客問我,道長平委,這世上最難降的妖魔是什么奈虾? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮廉赔,結果婚禮上肉微,老公的妹妹穿的比我還像新娘。我一直安慰自己蜡塌,他們只是感情好碉纳,可當我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著馏艾,像睡著了一般劳曹。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上琅摩,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天铁孵,我揣著相機與錄音,去河邊找鬼房资。 笑死蜕劝,一個胖子當著我的面吹牛,可吹牛的內容都是我干的志膀。 我是一名探鬼主播熙宇,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼溉浙!你這毒婦竟也來了烫止?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤戳稽,失蹤者是張志新(化名)和其女友劉穎馆蠕,沒想到半個月后期升,有當地人在樹林里發(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡互躬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年播赁,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吼渡。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡容为,死狀恐怖,靈堂內的尸體忽然破棺而出寺酪,到底是詐尸還是另有隱情坎背,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布寄雀,位于F島的核電站得滤,受9級特大地震影響,放射性物質發(fā)生泄漏盒犹。R本人自食惡果不足惜懂更,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望急膀。 院中可真熱鬧沮协,春花似錦、人聲如沸脖阵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽命黔。三九已至,卻和暖如春就斤,著一層夾襖步出監(jiān)牢的瞬間悍募,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工洋机, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留坠宴,地道東北人。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓绷旗,卻偏偏與公主長得像喜鼓,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子衔肢,可洞房花燭夜當晚...
    茶點故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內容