多執行緒之物件及變數的併發訪問 五 資料髒讀

2021-09-27 12:20:13 字數 2072 閱讀 6915

在前面文章的學習中,我們一直都在圍繞 synchronized 來講述,在方法沒有同步處理的時候,多個執行緒訪問乙個例項變數的時候,這個值已經被其他的執行緒更改過了,所以會出現資料髒讀(dirtyread),這個資料髒讀也出現了好多次,那麼本文就來看看到底是什麼東西

執行緒資料髒讀跟資料庫的事務髒讀又有一點不一樣,關於事務髒讀可以了解下另一篇文章:mysql 事務特性以及隔離級別

這裡示例乙個髒讀:

說明:

(1)t1 時刻,開始主線程進入

(2)t2 時刻,建立的新的執行緒 thread-

0 啟動,進入內部邏輯,將 username 賦值為 usernameb,然後開始睡眠 5s,同時 main 執行緒進入,開始睡眠 1s

(3)t3 時刻 = t2 時刻,兩個執行緒同時睡眠

(4)t4 時刻,thread-

0 仍然在睡,main 喚醒往下執行**,user 呼叫 getvalue 輸出值: `username = usernameb, password = passworda`

(5)t5 時刻,也就是在 t4 4s 後,繼續執行下面**,將 password 賦值為 passwordb ,而後輸出:`username=usernameb, password=passwordb`

由上,可以看到,main 執行緒讀取到了 thread-

0 執行緒執行**到一半的資料,造成了資料髒讀

解決上述髒讀的辦法簡單有兩個:

(1)thread-

0 睡眠的時候,不讓 main 執行緒呼叫這個物件的方法

(2)thread-

0 睡眠的時候,讓 main 也繼續睡眠,睡眠時間直到 thread-

0 執行完畢

在 user 類裡,將 getvalue 方法也加上 synchronized 同步鎖,對物件鎖住

可以看到 thread-0 執行緒獲取到物件鎖以後, main 無法執行 getvalue 只有等 thread-0 睡眠五秒以後,喚醒重新執行下面的**, main 執行緒才執行 getvalue 方法,這樣就不會造成資料髒讀

將 main 執行緒的睡眠時間增加到 7s ,也就是至少要大於 thread-0 的睡眠時間

如圖所示,增加 main 執行緒的睡眠時間以後,當 thread-0 睡眠五秒以後喚醒, main 執行緒仍然在睡眠,因此 thread-0 繼續往下執行代賦值,第七秒時, main 執行緒喚醒執行 getvalue 方法,輸出username = usernameb, password = passwordb,沒有出現資料髒讀,是理想的結果

Java多執行緒摘要 物件及變數的併發訪問

1 非執行緒安全 問題在於 例項變數 中,如果是方法內部的私有變數,則不存在 非執行緒安全 問題.2 關鍵字synchronized取得的都是物件鎖,而不是把一段 或方法 函式 當做鎖,所以哪個執行緒先執行synchronized關鍵字的方法,哪個執行緒就持有該方法所屬物件的鎖lock,那麼其他執行...

多執行緒2 物件及例項變數的併發訪問

1 方法全部未同步 隨機呼叫,且是非同步呼叫 2 乙個被同步乙個未同步 呼叫同步方法的執行緒先加鎖。但呼叫未同步方法的執行緒可以非同步載入。3 方法全部被同步 隨機順序執行第乙個同步的執行緒。該執行緒獲得當前方法的lock。若此時其它執行緒呼叫其它同步方法,需等待以加鎖方法全部執行完釋放lock。髒...

物件及變數的併發訪問

10 volatile的作用是強制從公共堆疊中讀取變數的值,而不是從執行緒私有資料堆疊取得變數的值 例項情況 在jvm被設定為 server模式時,為了執行緒的執行效率,執行緒一直在私有堆疊中取得執行緒變數的值,11 volatile增加了例項變數在多執行緒之間的可見性,但它卻不具有同步性,也就不具...