在約http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html底部,它說:爲什麼在雙重檢查鎖定中不可變對象是安全的?
雙檢鎖不可變對象
如果Helper是不可變對象,使得所有助手的字段是決賽,然後雙擊 - 檢查鎖定將無需使用易失性字段。這個想法是,對一個不可變對象(比如一個String或一個Integer)的引用應該和int或者float類似。讀取和寫入對不可變對象的引用是原子的。
樣品和一個可變的解釋如下:
// Broken multithreaded version
// "Double-Checked Locking" idiom
class Foo {
private Helper helper = null;
public Helper getHelper() {
if (helper == null)
synchronized(this) {
if (helper == null)
helper = new Helper();
}
return helper;
}
// other functions and members...
}
第一個原因,它不工作
最明顯的原因,它不工作它,初始化助手對象和寫入助手字段的寫入操作可以完成或不按順序感知。因此,調用getHelper()的線程可以看到對助手對象的非空引用,但請參閱助手對象的字段的默認值,而不是在構造函數中設置的值。
如果編譯器內聯調用構造函數,那麼如果編譯器可以證明構造函數不能拋出異常或執行同步,則初始化對象和寫入輔助對象字段的寫入操作可以自由重新排序。
即使編譯器沒有對這些寫入重新排序,在多處理器上,處理器或內存系統可能會重新排列這些寫入,如在另一個處理器上運行的線程所感知的那樣。
我的問題是:爲什麼不可變的類沒有問題?我無法看到重新排序與班級是否可變的任何關係。
謝謝
我認爲你的術語「完全初始化」意味着與你的鏈接中的東西有所不同? 「一個對象在其構造函數完成時被認爲是完全初始化的,一個線程只能在該對象被完全初始化後才能看到對象的引用,保證能夠看到該對象最終字段的正確初始化值。 – 2014-10-29 01:56:55
不,它是相同的:在調用'new Helper()'之後,JMM保證final字段已經被初始化,但沒有說可能或未被初始化的常規字段。 – assylias 2014-10-29 07:03:23