1. 程式人生 > >從火車站車次公示欄來學Java讀寫鎖

從火車站車次公示欄來學Java讀寫鎖

Java多執行緒併發之讀寫鎖

本文主要內容:讀寫鎖的理論;通過生活中例子來理解讀寫鎖;讀寫鎖的程式碼演示;讀寫鎖總結。通過理論(總結)-例子-程式碼-然後再次總結,這四個步驟來讓大家對讀寫鎖的深刻理解。

本篇是《凱哥(凱哥Java:kagejava)併發程式設計學習》系列之《Lock系列》教程的第七篇:《Java併發包下鎖學習第七篇:讀寫鎖》。

一:讀寫鎖的理論

什麼是讀寫鎖?

多個執行緒同時讀一個資源類是沒有任何問題的,所以為了滿足在併發的情況下,讀取共享資源應該是可以同時進行的;但是,如果一個執行緒想要去寫共享資源,就不應該再有其他執行緒可以對該共享資源進行讀或者是寫操作了。

即讀寫鎖在同一時刻可以允許多個多執行緒訪問,但是在寫執行緒訪問的時候,所有的讀執行緒和其他寫執行緒都會被阻塞。讀寫鎖實際維護了一對鎖,一個讀鎖,一個寫鎖,通過分離讀鎖和寫鎖,使得其併發性比獨佔式鎖(排他鎖)有了很大的提升。

為什麼需要讀寫鎖?

通過前面文章的學習,我們知道了ReentrantLock(下文簡稱:RLock)物件了。Rlock比起synchronized(下文簡稱Sync)來說有三個優點:RLock可以被中斷;RLock可以有公平鎖;RLock可以繫結多個條件。那麼既然RLock比Sync有這麼多優點,為什麼還需要讀寫鎖呢?

那是因為RLock是獨佔式(排他) 鎖,即當執行緒1獲取到資源的時候,其他執行緒不能再來操作共享資源了。就算是RLock的操作是讀取的時候,其他執行緒也不能讀取共享資源的操作。這在現實生活中是不符合邏輯的(在下文神話中讀寫鎖的例子中我們就能體會到為什麼不符合邏輯的),而且效能也比較慢。所以就有了讀寫鎖的出現。

二:讀寫鎖的理解

生活中讀寫鎖的例子

例子一:我們大家去火車站乘車的時候,有個大大的公示螢幕,會告訴大家當前車次是否晚點。顯示屏是給給所有乘客看的,如果火車晚點,對應車次後面就會被修改成晚點大約xxx分鐘。這個修改的動作只能是火車站內部人員來操作的,我們乘客是不能操作的。這個過程,站在併發角度來分析的的話:電子螢幕是共享資料;千千萬萬的乘客是不同的執行緒;火車站內部工作人員也是不同的執行緒;乘客是讀資源的執行緒,當一個執行緒來讀取的時候,其他執行緒也可以讀取操作的;火車站內部工作人員修改火車資訊的時候,同時只能有一個工作人員來修改,不能兩個都來修改。如果兩個都來修改的話,上一秒顯示晚點1min,下一秒顯示正常。這個是不行的,乘客有可能會錯過乘車的。所以修改的時候同時只能由一個工作人員來修改。

例子二:我們在玩王者榮耀的時候,有時候會遇到停服更新的。在不更新前,所有玩家都可以玩,當停服更新的時候,所有玩家就不能玩了。這個操作在併發角度來說:千千萬萬的玩家是讀共享資源的;遊戲維護者是寫操作的。當停服更新的時候,讀操作就被阻塞了,只能等寫操作,也就是更新完成後,才可以接著玩。

通過上面兩個例子我們可以分析到讀寫鎖的三個參與者:共享資源;讀物件;寫物件。而且讀和寫一般是分離的。

三:讀寫鎖的程式碼演示

我們就用火車站進站案例來模擬:

 

未使用鎖的時候

先來看看螢幕物件:

 

再來看看多個工作人員更新操作及多個乘客獲取操作:

 

檢視執行結果:

 

從執行結果中,我們可以發現當工號未13的還沒有更新完車次資訊的時候,工號12和14的員工也來更新了。這種操作是不允許的。因為寫操作要原子性,要獨佔。當工作人員甲在修改的時候車次資訊的時候,其他工作人員不能同時修改同一個車次資訊了。而且從乘客獲取車次資訊的資料來看,獲取到的只是工號是13的。這個時候獲取到的資料不一定是正確的了。所以,不使用鎖是不行的。

使用排他鎖

如果使用獨佔式做的話,我們檢視執行結果:

 

從執行結果來看,再讀取的時候,需要一個一個讀取的。當16號乘客檢視的時候,17號乘客是不能檢視的。這個是不符合實際業務邏輯的。所以,獨佔式(排他鎖)RLock在這裡不適合。我們再來看看讀寫鎖:

使用讀寫鎖

先來看看使用讀寫鎖的螢幕物件

 

再來看看執行結果:

 

從執行結果中,我們可以看到,工作人員是一個一個的操作完成的。當14號操作完成之後,13號和12號才可以操作的。這個符號我們正常的業務。乘客讀取的時候,讀取到的都是最後一次更新,這個也符合我們的業務。所以,通過讀寫鎖來操作車站螢幕是可以的。

 

四:讀寫鎖總結

4.1:wrLock類物件

 

同樣包含了公平鎖和非公平鎖。

其中ReadLock是讀鎖物件;WriteLock是寫鎖物件。

4.2:使用語法

讀操作使用ReadLock

編輯

寫操作的時候,使用WriteLock物件:

 

4.3:總結

讀寫鎖(ReentrantReadWriteLock),凱哥就簡寫rwLock。也可以實現公平和非公平的。其內部維護了一對鎖:一個讀鎖(ReadLock物件),一個寫鎖(writeLock物件),通過讀寫分離的方式來提高併發效能。讀寫鎖也叫共享鎖。其共享是在讀資料的時候,可以讓多個執行緒同時進行讀操作的。在寫的時候具有排他性,其他讀或者寫操作都要被阻塞。

一般情況下,讀寫鎖的效能都會比排他鎖效能好,那是因為,大多數場景讀操作多於寫操作的。在讀多與寫的場景下,讀寫鎖能夠提供比排他鎖更好的並效能和吞吐量。

    ​    ​    ​    ​    ​    ​    ​    ​    ​    ​    ​    ​    ​    ​    ​歡迎來聊~

&n