您好,登錄后才能下訂單哦!
這篇文章主要講解了“java中如何用一把鎖保護多個資源”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“java中如何用一把鎖保護多個資源”吧!
如果多個資源沒有關系,那就是保護一個資源模型的復制,同樣非常簡單,且看下圖:
比如現實中銀行取款和修改密碼操作。 銀行取款操作對應的資源是「余額」, 修改密碼操作對應的資源是「密碼」,余額和密碼兩個資源完全沒有關系,所以各自用自家的鎖保護自家的資源就好了
如果多個資源沒有關系,程序猿的世界該有多美好,可惜并不是,我們保護的資源多數情況都有關聯關系
拿經典的銀行轉賬案例來說明,賬戶 A 給賬戶 B 轉賬,賬戶 A 余額減少 100 元,賬戶 B 余額增加 100 元,這個操作要是原子性的,那么資源「A 余額」和資源「B 余額」就這樣"有了關系",先來看程序:
class Account { private int balance; // 轉賬 synchronized void transfer( Account target, int amt){ if (this.balance > amt) { this.balance -= amt; target.balance += amt; } } }
用 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 執行 transfer 方法鎖定的是 A 的實例(A.this),并沒有鎖定 B 的實例
線程 2 執行 transfer 方法鎖定的是 B 的實例(B.this),并沒有鎖定 C 的實例
所以線程 1 和線程 2 可以同時進入 transfer 臨界區,上面你認為對的模型其實就會變成這個樣子:
還記得 happens-before 規則 這篇文章提到的監視器鎖規則和傳遞性規則嗎?
####監視器鎖規則 對一個鎖的解鎖 happens-before 于隨后對這個鎖的加鎖 ####傳遞性規則 如果 A happens-before B, 且 B happens-before C, 那么 A happens-before C
資源 B.balance 存在于兩個"臨界區"中,所以這個"臨界區"對 B.balance 來說形同虛設,也就不滿足監視器鎖規則,進而導致傳遞性規則也不生效,說白了,前序線程的更改結果對后一個線程不可見
這樣最終導致:
**賬戶 B 的余額可能是 100: ** 線程 1 寫 B.balance 100(balance = 300) 先于 線程 2 寫 B.balance(balance = 100),也就是說線程 1 的結果會被線程 2 覆蓋,導致最終賬戶 B 的余額為 100
賬戶 B 的余額可能是 300: 與上述情況相反,線程 1 寫 B.balance 100(balance = 300) 后于 線程 2 寫 B.balance(balance = 100),也就是說線程 2 的結果線程 1 覆蓋,導致最終賬戶 B 的余額為 300
就是不能得到我們理想結果 200,感覺生活無比的艱難,那怎么辦呢?
上面的問題就是為資源創建的鎖不能保護所有關聯的資源,那我們就想辦法解決這個問題,來看下面代碼:
class Account { private int balance; // 轉賬 void transfer(Account target, int amt){ synchronized(Account.class) { if (this.balance > amt) { this.balance -= amt; target.balance += amt; } } } }
我們將 this 鎖變為 Account.class 鎖,Account.class 是虛擬機加載 Account 類時創建的,肯定是唯一的(雙親委派模型解釋了為何該對象是唯一的), 所有 Account 對象都共享 Account.class, 也就是說,Account.class 鎖能保護所有 Account 對象,我們將上面程序再用模型解釋一下
感謝各位的閱讀,以上就是“java中如何用一把鎖保護多個資源”的內容了,經過本文的學習后,相信大家對java中如何用一把鎖保護多個資源這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。