java线程同步——竞争条件的荔枝+锁对象
生活随笔
收集整理的這篇文章主要介紹了
java线程同步——竞争条件的荔枝+锁对象
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
【0】README
0.1) 本文描述轉自 core java volume 1, 源代碼為原創,旨在理解 java線程同步——競爭條件的荔枝+鎖對象 的相關知識;
0.2) for full source code, please visit https://github.com/pacosonTang/core-java-volume/blob/master/chapter14/ThreadFive.java
【1】競爭條件的荔枝
1.1)某銀行有若干個賬戶(我們這里設置為4個),且初始余額均為10000; 賬戶間存在著轉賬操作;
Attention):在模擬這個程序的過程中, 不清楚在某一時刻某銀行的賬戶轉賬多少錢,但是其總金額應該是不變的, 因為我們所做的一切不過是從銀行的一個賬戶轉賬到另一個賬戶(干貨——無論怎樣轉賬,總金額應該是不變的,始終為40000)。
對上述運行結果的分析(Analysis):
- A1)問題在于這不是一個原子操作, 該指令可能被如下處理:
- step1)將 account[to] 加載到寄存器;
- step2)增加 amount 到 account[to]上;
- step3)將結果寫回 account[to];
- A2)現在線程1 執行step1 + step2, 然后CPU切換到執行線程2;
- A2.1)假設線程2修改了account[to]的值;
- A2.2)之后,線程1被喚醒,然后進行 step3;
- A3)那顯然, 線程1的step3操作重寫了 線程2的寫入結果(線程1擦除線程2所做的更新), 所以就出現了最終的總金額不等于 40000的錯誤結果;
- A4)如果要保持結果的合理性,只需要達到一個目的,就是將對賬戶余額的訪問加以限制,每次只能有一個線程在訪問。這樣就能保證賬戶中余額數據的合理性了。
1.2)解決方法:
- 1.2.1)使用同步塊(synchronized):在使用同步代碼塊時候,應該指定在哪個對象上同步,也就是說要獲取哪個對象的鎖。例如:(干貨——無論怎樣轉賬,總金額應該是不變的,始終為40000)。
- 1.2.2)使用同步方法:(干貨——無論怎樣轉賬,總金額應該是不變的,始終為40000)。
【2】鎖對象
2.1)有兩種方法防止代碼塊受并發訪問的干擾:
- 2.1.1) synchronized 關鍵字, 構造同步塊,或是同步方法;(如1.2中解決方法 所示)
- 2.1.2) java 5.0 引入的 ReentrantLock 類;
2.2)用ReentrantLock保護代碼塊的基本結構
myLock.lock() try {} finally {myLock.unlock() }- 2.2.1)這一結構確保了 任何時刻只有一個線程進入臨界區域, 一旦一個線程封鎖了鎖對象,其他任何線程都無法通過lock語句。 當其他線程調用 lock 時, 它們會被阻塞,直到第一個線程釋放鎖對象;
Warning)把解鎖操作包括在了 finally 子句中是至關重要的。 如果在臨界區的代碼拋出異常, 鎖必須被釋放, 否則, 其他線程將永遠阻塞下去;
Attention)
- A1)鎖是可重入的, 因為線程可以重復地獲得已持有的鎖;
- A2)鎖保持一個持有計數來跟蹤對 lock 方法的嵌套調用, 線程在每一次調用lock 都要調用 unlock 來釋放鎖;
- A3)由于這一特性, 被一個鎖保護起來的代碼可以調用另一個使用相同的鎖的方法;
總結
以上是生活随笔為你收集整理的java线程同步——竞争条件的荔枝+锁对象的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 笑看天下什么意思 笑看天下意思是什么
- 下一篇: java线程同步——条件对象+synch