我試圖了解final欄位在多執行緒環境中的作用。
我閱讀了這些相關的帖子:
final 欄位和執行緒安全
Java 并發:final 欄位(在建構式中初始化)是執行緒安全的嗎?
Java:最終欄位凍結可從最終欄位訪問的物件
并嘗試模擬final欄位將阻止執行緒處理未完全構造的物件的情況。
public class Main {
public static void main(String[] args) {
new _Thread().start();
new Dummy();
}
static class _Thread extends Thread {
static Dummy dummy;
@Override
public void run() {
System.out.println(dummy.getIntegers().size() == 10_000);
}
}
static class Dummy {
private final List<Integer> integers = new ArrayList<>();
public Dummy() {
_Thread.dummy = this;
for (int a = 0; a < 10_000; a ) {
integers.add(a);
}
}
public List<Integer> getIntegers() {
return integers;
}
}
}
所以據我所知,_Thread將停止執行getIntegers()并等待回圈完成填充集合。但無論finalfield是否有修飾符integers,結果run()都是不可預知的。我也知道有 NPE 的可能性。
uj5u.com熱心網友回復:
在final這里沒有區別。代碼不是執行緒安全的,無論是否final存在。
這不是執行緒安全的有兩個原因。
您
Dummy在其建構式完成之前發布(并可能改變)狀態。無論變數是否為 ,這都是不安全的final。您正在
getIntegers()呼叫中回傳一個共享的可變物件。所以這意味著呼叫者可以改變它,第二個呼叫者可能會或可能不會看到結果......由于缺乏同步。再次final與此無關。
的執行緒安全保證final是有限的。這里是什么JLS說:
final欄位還允許程式員在沒有同步的情況下實作執行緒安全的不可變物件。執行緒安全的不可變物件被所有執行緒視為不可變的,即使使用資料競爭在執行緒之間傳遞對不可變物件的參考也是如此。這可以提供安全保證,防止錯誤或惡意代碼濫用不可變類。final必須正確使用欄位以提供不變性保證。當一個物件的建構式完成時,它被認為是完全初始化的。只有在物件完全初始化后才能看到對物件的參考的執行緒可以保證看到該物件
final欄位的正確初始化值。
要點是這些final保證僅適用于不可變物件,并且它們僅在物件的建構式回傳之后才適用。
在您的示例中,不滿足這些先決條件中的任何一個。因此,保證不適用。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/359330.html
