共享資源那麼多,如何用一把鎖保護多個資源?

2021-09-28 16:36:30 字數 2657 閱讀 9569

當我們要保護單個資源並對其進行修改其實很簡單,只需按照下圖分三步走

建立受保護資源 r 的鎖

加鎖進入臨界區

解鎖走出臨界區

上圖的關鍵是「r1 的鎖保護 r1」的指向關係是否正確

如果都是保護單個資源這樣簡單,程式猿的世界該有多美好,可惜並不是,通常我們需要保護多個資源

如果多個資源沒有關係,那就是保護乙個資源模型的複製,同樣非常簡單,且看下圖:

比如現實中銀行取款和修改密碼操作。

銀行取款操作對應的資源是「餘額」, 修改密碼操作對應的資源是「密碼」,餘額和密碼兩個資源完全沒有關係,所以各自用自家的鎖保護自家的資源就好了

如果多個資源沒有關係,程式猿的世界該有多美好,可惜並不是,我們保護的資源多數情況都有關聯關係

拿經典的銀行轉賬案例來說明,賬戶 a 給賬戶 b 轉賬,賬戶 a 餘額減少 100 元,賬戶 b 餘額增加 100 元,這個操作要是原子性的,那麼資源「a 餘額」和資源「b 餘額」就這樣"有了關係",先來看程式:

class account } }

用 synchronized 直接保護 transfer 方法,然後操作資源「a 餘額」和資源「b 餘額」就可以了

⚠️: 真的是這樣嗎?

先停止向下看,在你的筆記本上按照文章開頭的三步走來畫個圖看一看,是否和下圖一樣呢?

我們通常容易忽略鎖和資源的指向關係,我們想當然的用鎖 this 來保護 target 資源了,也就沒有起到保護作用

假設 a,b,c 賬戶初始餘額都是 200 原,a 向 b 轉賬 100,b 向 c 轉賬 100

我們期盼最終的結果是:賬戶 a 餘額: 100 元賬戶 b 餘額: 200 元賬戶 c 餘額: 300 元

假執行緒 1「a 向 b 轉賬」與執行緒 2「b 向 c 轉賬」兩個操作同時執行,根據 jmm 模型可知,執行緒 1 和執行緒 2 讀取執行緒 b 當前的餘額都是 200 元:

所以執行緒 1 和執行緒 2 可以同時進入 transfer 臨界區,上面你認為對的模型其實就會變成這個樣子:

監視器鎖規則

傳遞性規則

資源 b.balance 存在於兩個"臨界區"中,所以這個"臨界區"對 b.balance 來說形同虛設,也就不滿足監視器鎖規則,進而導致傳遞性規則也不生效,說白了,前序執行緒的更改結果對後乙個執行緒不可見這樣最終導致:

就是不能得到我們理想結果 200,感覺生活無比的艱難,那怎麼辦呢?

上面的問題就是為資源建立的鎖不能保護所有關聯的資源,那我們就想辦法解決這個問題,來看下面**:

class account }} 

}

我們將 this 鎖變為 account.class 鎖,account.class 是虛擬機器載入 account 類時建立的,肯定是唯一的(雙親委派模型解釋了為何該物件是唯一的), 所有 account 物件都共享 account.class, 也就是說,account.class 鎖能保護所有 account 物件,我們將上面程式再用模型解釋一下

到這裡關於鎖和資源的關係你應該了解的更加透徹了,單個資源和多個無關聯資源的情形都很好處理,為各自資源建立相應的鎖就好,如果多個資源有關聯,為了讓鎖起到保護作用,我們需要將鎖的粒度變大,比如將 this 鎖變成了 account.class 鎖。

轉賬業務非常常見,併發量非常大,如果我們將鎖的粒度都提公升到 account.class 這個級別(分久必合),假設每次轉賬業務都很耗時,那麼顯然這個鎖的效能是比較低的,所以接下來的文章,我們還會繼續優化這個模型,選擇合適的鎖粒度,同時能保護多個有關聯的資源

我們的鎖粒度雖然大,但是我們保障了賬戶的安全,所以併發程式設計可以先保證事情做對,遇到瓶頸了,慢慢優化改變相應的模型就好了,當然熟練理解這個模型以後,一步到位的併發程式設計模型當然是極好的......

偏向鎖,輕量鎖,重量鎖是不是和我們這節內容有異曲同工之處呢?

提前想一下,我們如何來優化這個模型呢?

這次走進併發的世界,請不要錯過

學併發程式設計,透徹理解這三個核心是關鍵

併發bug之源有三,請睜大眼睛看清它們

解決原子性問題?你首先需要的是巨集觀理解

面試併發volatile關鍵字時,我們應該具備哪些談資?

共享資源那麼多,如何用一把鎖保護多個資源?

當我們要保護單個資源並對其進行修改其實很簡單,只需按照下圖分三步走 建立受保護資源 r 的鎖 加鎖進入臨界區 解鎖走出臨界區 上圖的關鍵是 r1 的鎖保護 r1 的指向關係是否正確 如果都是保護單個資源這樣簡單,程式猿的世界該有多美好,可惜並不是,通常我們需要保護多個資源 如果多個資源沒有關係,那就...

會計那麼多,你如何提公升自己的財務能力?

學習,是伴隨著每乙個專業人員不可缺少的。認識很多拿著高薪的會計高管,他們不乏學歷 背景都一開始較弱,只是因為在乙個領域裡面辛勤耕耘而成為這個領域的專精之士,從而獲得了與他們價值匹配的薪酬。接下來我將具體講講會計人員如何提高自己。一 持續不斷地補充專業技能 遇到過很多人都很聰明,也有很強的好奇心,對待...

市面上資料庫種類那麼多,如何選擇

技術真的是日新月異,關係型資料庫在資料庫儲存界稱霸這麼多年後,市面上各種資料庫如雨後春筍蓬勃發展,似乎關係型資料庫也地位不保,我前段時間和同事聊天,聽到他們經常說的現在市面上的nosql資料庫完全可以替代現有的關係型資料庫,可是事實真的如此嗎,我們一起就市面上現在比較流行的各類資料庫,做乙個對比 真...