如果我們有以下類,則根據 Java Concurrency in Action:
public class Wrapper {
private int num;
public Wrapper(int num) {
this.num = num;
}
public void assertCorrectness() {
if (num != num)
throw new AssertionError("This is false");
}
}
我們初始化這個類的一個實體并以非安全的方式發布它(例如通過一個簡單的公共欄位),那么如果從另一個執行緒呼叫,assertCorrectness() 可能確實會拋出一個 AssertionError。換句話說,這意味著另一個執行緒可能會看到對實體的最新參考,但實體本身的狀態可能是過時的(因此執行緒可以看到物件存在但它在部分構造/不一致的狀態)。
另一方面,據說通過 volatile 參考發布此類的實體被認為是安全的。然而,我的理解是 volatile 只是保證任何執行緒將始終看到參考的最新版本,而不是被參考的物件的狀態。因此我們可以確定,如果一個執行緒將 Wrapper 類的新實體分配給 volatile 欄位,那么所有其他執行緒都會看到該參考已更新。但是是否存在他們仍然會看到處于不一致/部分構造狀態的物件的風險?
uj5u.com熱心網友回復:
不,因為volatile被使用建立了先發生的關系。如果沒有它,則允許進行各種重新排序和其他事情,這使得不一致的狀態成為可能,但有了它,JVM 必須為您提供預期的結果。
在這種情況下volatile,不用于可見性效果(執行緒查看最新值),而是用于 happpens-before 提供的安全發布。在解釋它的使用時,這個特性volatile經常被忽略。
uj5u.com熱心網友回復:
上面的答案是正確的。
請記住, effectively immutable safe publication在某些情況下行為不直觀。
例如:
如果
- 首先
thread 1安全地發布物件o到thread 2 - 然后
thread 2不安全地將物件發布o到thread 3
最后
thread 3可以看到物件o處于不一致的狀態
參見[1]和[2]- 首先
這也是
真正的不可變物件沒有這樣的問題。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/430557.html
上一篇:使用排序物件時,Powershell管道變數丟失/覆寫。選擇?
下一篇:執行緒會提高這個回圈的速度嗎?
