前面的示例中已經實現(xiàn)了多個線程調用同一個方法時,為了避免數(shù)據(jù)出現(xiàn)交叉的情況,使用synchronized關鍵字來進行方法同步。
雖然在賦值時進行了同步,但在取值時有可能出現(xiàn)一些意想不到的情況,這種情況就是臟讀。臟讀的情況發(fā)生在讀取變量時,此值已經被其它線程更改過。
例如:

同步方法setValue()的鎖屬于類PublicVar的實例。下面創(chuàng)建線程類:

運行類:

運行結果:

出現(xiàn)臟讀是因為getValue()方法并不是同步的,所以可以在任意時候進行調用,解決辦法當然也就是加上同步synchronized關鍵字:

運行結果:

可見,方法getValue和setValue被依次執(zhí)行,通過這個實驗,不僅要知道臟讀是通過synchronized關鍵字解決的,還要知道下面的內容:
當A線程調用anyObject對象加入synchronized關鍵字的X方法時,A線程就獲得了X方法鎖,更準確的講,是獲得了對象的鎖,所以其它線程必須等A線程執(zhí)行完畢,才可以調用X方法,但是B線程可以隨意代用其它非synchronized同步的方法。
當A線程調用 anyObject 對象加入synchronized關鍵字的X方法時,A線程就獲得了X方法所在對象的鎖,所以其它線程必須等A線程執(zhí)行完畢才可以調用X方法,而B線程如果調用聲明了synchronized關鍵字的非X方法時,必須等A線程將X方法執(zhí)行完,也就是釋放對象鎖后才可以調用。這時A線程已經執(zhí)行了一個完整的任務,也就是說username和password這兩個實例變量已經同時被賦值,不存在臟讀的基本環(huán)境。
臟讀一定會出現(xiàn)操作實例變量的情況下,這就是不同線程爭搶實例變量的結果。