[轉載]Java8并發(fā)教程-Synchronization and Locks

原文:Java8并發(fā)教程-Synchronization and Locks

這是該系列教程的第二篇.其中用到了一個工具類,和其中的兩個方法.如下圖所示:

image.png

1 Synchronized

在第一篇教程中,我們已經介紹了如何通過** Executor Service**來并行執(zhí)行任務.但是,這也引入了一個新的問題.即我們如何并發(fā)的訪問那些共享的變量.假設我們打算用多個線程來并發(fā)地增加一個數字.我們使用下面的代碼:

image.png
image.png

我們可以看到,其結果不是正確的結果,即10000.那為什么會出現這種情況呢?這是因為我們不恰當的讓多個線程并發(fā)的訪問并設置共享變量而造成的.本例中,共享變量即為count.

當執(zhí)行一個加法操作時,需要按三步進行:
1.讀取當前值
2.使當前值加一
3.將這個新值寫入到變量中.
如果有兩個線程同時執(zhí)行第一步,即讀取當前值,它們獲得了相同的值,就會造成寫丟失.也就是說,第二個線程在執(zhí)行第三步時,會覆蓋掉第一個進程寫入的結果.

Java中,我們可以通過使用synchronized關鍵字,來防止這種情況的出現.

我們使用synchronized關鍵字來改寫上面的執(zhí)行加法操作的函數:

image.png

現在我們讓線程通過執(zhí)行這個函數來并發(fā)地進行加法操作:

image.png

現在我們可以看到,結果是正確的.不管你執(zhí)行多少次,結果都是正確的.

synchronized關鍵字,不僅可以用在函數上,還可以用在代碼塊中:

image.png

synchronized關鍵字的內部, Java使用一個叫做monitor的東西來管理它,monitor也被稱作monitor lock 或 intrinsic lock. monitor是和對象關聯在一起的,每個synchronized的方法,針對一個對象,都使用同一個monitor.

synchronized也有可重入的特性,也就是說,即使當前線程已經占有了鎖,它還是可以請求相同的鎖的,這就避免了死鎖的產生.

2 Locks

除了通過使用synchronized這種隱式鎖來進行同步,Concurrency API中,還提供了大量顯式鎖.通過使用這些顯式鎖,我們能對并發(fā)進行更好的控制.

下面我們會一個個的介紹這些顯式鎖.

3 ReentrantLock

這個鎖是一個互斥鎖.它也實現了** synchronized**中的隱式鎖的基本特性,當然,它還是有一些自己的特性的.這個鎖也是可重入的.

我們使用ReentrantLock來實現上面的例子:

image.png

我們通過lock()方法來獲得鎖,而通過unlock()方法,來釋放鎖.我們要用try/catch來包裝我們的代碼,來防止鎖得不到釋放.這個函數也是線程安全的.如果其他線程在這個鎖沒有釋放之前,想要獲得鎖,就會被阻塞.只有一個線程能夠同時占有鎖.

除此之外,鎖還提供了其他的函數,如下圖所示:

image.png

第一個任務獲得鎖,然后暫停一秒鐘.而第二個任務則獲取鎖的當前狀態(tài),并將其輸出出來.

image.png

tryLock()會嘗試獲取鎖,而不會像lock()方法一樣,阻塞線程.我們需要在執(zhí)行那些需要訪問共享變量的操作之前,檢查一下其返回值,以防止不同步的情況.

4 ReadWriteLock

ReadWriteLock包含一對鎖,分別用于對共享變量的讀和寫操作.ReadWriteLock背后的原理是,如果當前沒有線程來修改共享變量,那么允許多個線程來訪問共享變量,而沒有什么危險.所以說,當沒有線程持有寫鎖的時候,可以有多個線程持有讀鎖.這在那些讀操作遠大于寫操作的場景中,極大的提高了性能和吞吐量.

image.png
image.png

在你執(zhí)行上面的代碼時,你會注意到,只有當寫鎖被釋放之后,后面的線程才會同時獲取到讀鎖.而不需要等第一個線程的讀鎖釋放之后,第二個線程才能獲取讀鎖.

5 StampedLock

Java8中,還增加了一種叫做StampedLock的鎖,這個鎖也有讀鎖和寫鎖,就跟上面的ReadWriteLock一樣.但是,和ReadWriteLock不同,它會返回一個long類型的值,我們可以通過這個值來釋放鎖,檢查鎖是否有效.另外,它還包含一種叫做樂觀鎖的鎖.

我們有下面的代碼:

image.png

我們通過readLock()方法來獲取讀鎖,通過writeLock()方法來獲取寫鎖.需要注意的是,StampedLock并沒有可重入的特性.如果沒有鎖可用,則調用上面的方法,會導致返回一個值,并阻塞線程,即使當前線程已經有鎖了.所以你使用這個鎖的時候,要小心,別出現死鎖的情況.

ReadWriteLock鎖一樣,要獲得讀鎖,必須等待寫鎖被釋放.

我們使用下面的這個例子,來了解樂觀鎖:

image.png

tryOptimisticRead()方法,會獲得一個樂觀讀鎖.它總會返回一個值,而不會阻塞當前線程.如果有線程持有寫鎖,則返回值是0.所以,我們需要通過lock.validate()方法來檢查一下返回值,來確定是否真的有讀鎖可用.

上面的代碼,輸出如下:

image.png

我們應當在獲取到樂觀鎖之后,就立即使用它.因為它隨時可能無效.與平常的讀鎖不同,樂觀鎖不會阻止其他的線程獲得寫鎖.也就是說,在一個線程占有樂觀鎖的時候,其他的線程還是可以獲取到寫鎖的,而不需要等待樂觀鎖被釋放.當其他線程獲得了寫鎖之后,樂觀鎖就失效了.即使那個線程后來又釋放了寫鎖.

所以,如果使用樂觀鎖的話,我們需要時刻驗證樂觀鎖是否還有效.特別是在執(zhí)行對共享變量的寫操作之前.

有時,我們需要將一個讀鎖轉換成寫鎖.StampedLock提供了tryConvertToWriteLock()這個方法,來進行轉換.

image.png

上面的那個任務,會先獲取讀鎖,并嘗試輸出count變量的值.但是當其等于0時,它會將讀鎖轉換成寫鎖,如果轉換成功,則將23賦給count.如果不成功,則直接通過lock.writeLock()來以阻塞的方式獲取寫鎖.然后將23賦給count.最后,再釋放鎖.

6 Semaphores

除了鎖,Concurrency API也支持信號量.鎖通常用于互斥的訪問某些資源,而信號量用于限制一定的線程可以同時訪問某些資源.

下面這個例子,演示了如何使用信號量:

image.png

Executor允許同時執(zhí)行十個線程,但是因為我們將信號量設置成了5.所以實際上,只有5個線程有機會來執(zhí)行操作.

輸出如下:

image.png

只有前五個線程,能夠獲得一個信號量,然后來執(zhí)行暫停五分鐘的操作.其他的線程,因為沒有信號量可以獲取了,就只能在控制臺打印處Could not acquire semaphore.

作者:AlstonWilliams
鏈接:http://www.reibang.com/p/053150087cd5
來源:簡書
簡書著作權歸作者所有呐籽,任何形式的轉載都請聯系作者獲得授權并注明出處。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末竹勉,一起剝皮案震驚了整個濱河市兆龙,隨后出現的幾起案子宛官,更是在濱河造成了極大的恐慌媒咳,老刑警劉巖迹缀,帶你破解...
    沈念sama閱讀 221,406評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件使碾,死亡現場離奇詭異,居然都是意外死亡祝懂,警方通過查閱死者的電腦和手機票摇,發(fā)現死者居然都...
    沈念sama閱讀 94,395評論 3 398
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來砚蓬,“玉大人矢门,你說我怎么就攤上這事』彝埽” “怎么了祟剔?”我有些...
    開封第一講書人閱讀 167,815評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長摩梧。 經常有香客問我物延,道長,這世上最難降的妖魔是什么障本? 我笑而不...
    開封第一講書人閱讀 59,537評論 1 296
  • 正文 為了忘掉前任教届,我火速辦了婚禮,結果婚禮上驾霜,老公的妹妹穿的比我還像新娘案训。我一直安慰自己,他們只是感情好粪糙,可當我...
    茶點故事閱讀 68,536評論 6 397
  • 文/花漫 我一把揭開白布强霎。 她就那樣靜靜地躺著,像睡著了一般蓉冈。 火紅的嫁衣襯著肌膚如雪城舞。 梳的紋絲不亂的頭發(fā)上轩触,一...
    開封第一講書人閱讀 52,184評論 1 308
  • 那天,我揣著相機與錄音家夺,去河邊找鬼脱柱。 笑死,一個胖子當著我的面吹牛拉馋,可吹牛的內容都是我干的榨为。 我是一名探鬼主播,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼煌茴,長吁一口氣:“原來是場噩夢啊……” “哼随闺!你這毒婦竟也來了?” 一聲冷哼從身側響起蔓腐,我...
    開封第一講書人閱讀 39,668評論 0 276
  • 序言:老撾萬榮一對情侶失蹤矩乐,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后回论,有當地人在樹林里發(fā)現了一具尸體散罕,經...
    沈念sama閱讀 46,212評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,299評論 3 340
  • 正文 我和宋清朗相戀三年透葛,在試婚紗的時候發(fā)現自己被綠了笨使。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,438評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡僚害,死狀恐怖硫椰,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情萨蚕,我是刑警寧澤靶草,帶...
    沈念sama閱讀 36,128評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站岳遥,受9級特大地震影響奕翔,放射性物質發(fā)生泄漏。R本人自食惡果不足惜浩蓉,卻給世界環(huán)境...
    茶點故事閱讀 41,807評論 3 333
  • 文/蒙蒙 一派继、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧捻艳,春花似錦驾窟、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,279評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春恩急,著一層夾襖步出監(jiān)牢的瞬間杉畜,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,395評論 1 272
  • 我被黑心中介騙來泰國打工衷恭, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留此叠,地道東北人。 一個月前我還...
    沈念sama閱讀 48,827評論 3 376
  • 正文 我出身青樓匾荆,卻偏偏與公主長得像拌蜘,于是被迫代替她去往敵國和親杆烁。 傳聞我的和親對象是個殘疾皇子牙丽,可洞房花燭夜當晚...
    茶點故事閱讀 45,446評論 2 359

推薦閱讀更多精彩內容