這是JCiP的一個例子。不可變的對象是否可以免於不適當的發佈?
public class Unsafe {
// Unsafe publication
public Holder holder;
public void initialize() {
holder = new Holder(42);
}
}
public class Holder {
private int n;
public Holder(int n) {
this.n = n;
}
public void assertSanity() {
if (n != n) {
throw new AssertionError("This statement is false.");
}
}
}
在第34頁:
[15]這裏的問題不是Holder類本身,而是 持有人不能正常出版。然而,通過聲明n字段是最終的,持有者可以被免疫 以不適當的公佈,其中 將使得Holder不可變;
而且從this answer:
最終規範(見@ andersoj的答案)保證 當構造函數返回時,最後一個字段會一直正確 (從所有線程中可見)初始化。
從wiki:
例如,在Java中,如果一個構造函數的調用具有 被內聯,則共享變量可能會立即更新一次 存儲已經撥出而內聯構造函數之前 初始化對象
我的問題是:
因爲:(可能是錯誤的,我不知道)
a)共享變量可能會在內聯構造函數初始化對象之前立即更新。
b)只有當構造函數返回時,最終字段才能保證正確初始化(如所有線程都可見)。
是否有可能其他線程看到默認值holder.n
? (即另一個線程在holder
構造函數返回之前獲得對holder
的引用。)
如果是這樣,那麼如何解釋下面的語句? 從JCiP:
持有人可以通過聲明n個 場是決賽,這將使持有人不變
編輯進行免疫出版不當。不可變對象的定義:
一個目的是不可變的,如果:
X及其狀態不能之後 結構進行修改;X中的所有其字段是最後; [12]和
X是適當地構成(在該參考文獻沒有施工期間逸出) 。
因此,根據定義,不可變對象沒有「this
引用轉義」問題。對?
但是,如果沒有聲明爲volatile,他們會遭受Out-of-order writes雙重檢查鎖定模式?
Java內存模型保證所有不可變對象的安全發佈,而不顯示同步,所有不可變對象的實例字段聲明爲final。 – scottb
@scottb錯誤。構造函數本身可以泄漏參考。 – chrylis