2016-03-20 20 views
3

は、次のコードを考えてみましょう:非最終静的フィールドの静的初期化は安全ですか?

public class Text { 
    private static ThreadLocal<CharsetEncoder> encoderFactory = 
    new ThreadLocal<CharsetEncoder>() { 
     @Override 
     protected CharsetEncoder initialValue() { 
     return Charset.forName("UTF-8").newEncoder(). 
      onMalformedInput(CodingErrorAction.REPORT). 
      onUnmappableCharacter(CodingErrorAction.REPORT); 
     } 
    }; 

    public static ByteBuffer encode(String string, boolean replace) 
     throws CharacterCodingException { 
    CharsetEncoder encoder = encoderFactory.get(); 
    ... 
    } 
} 

encode()encoderFactoryをアクセスラインは、これまでの同時状況でNullPointerExceptionを投げることはできますか?

はい、このケースでは、encoderFactoryは最終的には簡単に宣言でき、この質問はやや疑問に思うことをよく認識しています。

ただし、私の興味はここでも上記のコードが安全にencoderFactoryを発行するかどうかです。もし私がJLS 12.4を理解していれば、そうでなければなりません。静的初期化のステップは、初期化されたクラスを見た後に、どのスレッドも初期化されていない状態(つまり、何も起こりません)で静的フィールドを見る可能性を残さないようです。私はJLSが静的初期化がメモリの壁を形成することを合理的に明らかにしたと思った。

明らかにこのようなNullPointerExceptionが観察されましたが、このフィールドを最終的に修正することで終了しました。それは確かに良いことですが、私はまだこのパターンでヌルポインタを見る方法を困惑しています。そうでなければ、より大きな問題が起こります。最終的でない静的フィールドの初期割り当ては、見えるようにする。

静的初期化がメモリバリアを提供するという前提が信頼できるもの(私はそれが信じている)だとすれば、必ずJDKのバグを指摘するでしょうか? JDKのバグ以外の理由が考えられますか?

答えて

1

それは12.4.2あたりとして、スレッドセーフになります。

Javaプログラミング言語はマルチスレッド化されているので、クラスやインタフェースの初期化は慎重に同期する必要があります。

クラスの初期化は、同時の状況で安全です。フィールドが最後に宣言されたかどうかに関わらず、すべてのスレッドがencodeを呼び出す機会を持つ前に、フィールドがロードされます。使用される参照タイプは違いをもたらさない(ThreadLocalを含む)。

さらに、初期化が行われる正確な手順について説明します。スレッドは、初期化が正常に完了するか、突然終了するまで通知されません(スローされた例外により、ExceptionInInitializerErrorになります)。

+0

ありがとうございました。それは私の読書でもあり、私はいつもその通りだと考えました。しかし、そのタイプのコードでは 'NullPointerException'が見られました。私は、JDKのバグを必ず指摘するでしょうか? JDKのバグ以外の理由が考えられますか? – sjlee

+0

@sjlee質問にスタックトレースを編集してください –

関連する問題