2016-08-07 4 views
1

Practice-オブジェクトのfinalとしてフィールドを作成すると、そのオブジェクトのnull参照を参照するスレッドは避けられますか?

でのJava並行処理から抽象/スニペット
// Unsafe publication 
public Holder holder; 

public void initialize(){ 
    holder = new holder(42); 
} 

2つのことは、不適切に発行されたオブジェクトと間違って行くことができます。他の スレッドはホルダーフィールドの無効な値を参照する可能性があり、値が の場合でも、 null参照または他の古い値を参照してください。しかし、他のスレッドでは、の最新の という値が表示されますが、 ホルダーの状態では無効です。状況をさらに予測しにくくするために、スレッドは が最初にフィールドを読み取ったときに失効した値を表示し、次に の値を返します。なぜassertSanityが AssertionErrorを投げることができるのですか。

は、基準は、別のスレッドに可視となるオブジェクトは、必ずしも、そのオブジェクトの状態が消費スレッド Ofcouse、それを修正する方法の一つは次のようになり

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."); 
    } 
} 

に表示されていることを意味しません行うには/作る

public volatile Holder holder; 

著者は

異なる的アプローチを提案しています

ホルダーが不変であれば、assertSanityはホルダーが適切に公表されなかった場合でも、 てAssertionErrorを投げることができませんでした。)

public class Holder{ 
     private final int n; 
//... 
} 

しかし、どのように?安全でない出版物はまだそこにあります。スレッドではまだnullの参照が得られていると思います。提案してください。

+0

関連http://stackoverflow.com/questions/16107683/improper-publication-of-java-object-reference and http://stackoverflow.com/a/6088679/1743880 – Tunaki

答えて

1

JLSは、最終的なフィールド

https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5

finalフィールドの特別な意味はまた、プログラマは同期せずに、スレッドセーフな不変オブジェクトを実装することができますについて説明します。スレッド間で不変オブジェクトへの参照を渡すためにデータ競合が使用されたとしても、スレッドセーフな不変オブジェクトはすべてのスレッドによって不変であると見なされます。 [...]。最終フィールドは、不変性の保証を提供するために正しく使用されなければなりません。

は、しかし、私は、あなたが全体の17.5

が「正しく使用しなければならない」実際に終了したコンストラクタを指し(そしてthisを免れませんでした)章と無反射をいじるを読むことをお勧め。あるhttp://www.angelikalanger.com/Articles/EffectiveJava/38.JMM-Overview/38.JMM-Overview.htmlからの翻訳

コンストラクタの端部は、メモリにすべての最終的な変数とdependendオブジェクトを書き込み、部分的フラッシュを引き起こします。 [...]。最終変数の最初の読み取りアクセスは、部分的リフレッシュを引き起こし、最終変数および依存オブジェクトをメモリからロードする。もう一つの参照は起こらない[...]。

関連する問題