2012-11-21 10 views
5

JCIPのセクション3.2.1「安全なコンストラクタの使用法」では、コンストラクタからの別のスレッドに「をリークすることに対する警告があります。たとえパブリケーションがコンストラクタの最後のステートメントであっても」です。その最後の部分は私には強すぎるように思えますし、それは正当化されていません。工事の後に何が起こるのですか?私は避けるように注意しなければなりません。例外はありますか?私は最近、私がこのことをやったいくつかのコードを提出したので、私は興味があります。私は、リファクタリングして戻ってくる正当性があるかどうかを決めたいと思っています。java:なぜこれをコンストラクタからエスケープできないようにする必要がありますか?

+1

http://msmvps.com/blogs/jon_skeet/archive/2010/09/02/don-t-let-this-get-away.aspx – SLaks

答えて

4

Javaメモリモデルに関する限り、コンストラクタ出口は最終フィールドのセマンティクスで役割を果たします。したがって、コンストラクタが終了する前か後であるかに違いがあります。

This works       This doesn't work 
------------------------------------------------------------- 

static Foo shared;     static Foo shared; 

class Foo       class Foo 
{         { 
    final int i;      final int i; 
    Foo()        Foo() 
    {         { 
     i = 1;        i = 1; 
              shared = this; 
    }         } 
}         } 

shared = new Foo();    new Foo(); 

は(注:sharedは揮発性ではなく、出版物は、データ競合を介してである)

2つの実施例の間の唯一の違いは、コンストラクタの出口の前または後sharedを割り当てています。 2番目の例では、割り当て後にi=1の順序を変更することができます。

ただし、パブリケーションが同期アクション(例:揮発性の変数を通して、それは大丈夫です。他のスレッドは完全に初期化されたオブジェクトを観察します。フィールドはfinalする必要はありません。

データレース(またはデータレースを通じて何かを行うこと)は、非常に慎重な推論が必要な非常にトリッキーなビジネスです。データ競争を避ければ、事態はずっと簡単になります。 コードにデータレースが含まれていない場合は、コンストラクタが終了する直前にthisがリークすることと、コンストラクタが終了した直後にパブリッシュすることに違いはありません。

4

いつでもコンストラクタから "最後のステートメントの[...]"を漏らすべきではありません。 thisは完全に構築されていないので、非常に奇妙なことが起こる可能性があります。非常によく似た質問については、this SO answerを参照してください。

4

あなたはそれがコンストラクタの最後の行だ場合でも、これを行うべきではありません

一つの理由は、JVMが許可されていることである(「this漏れ」として知られている)コンストラクタのうち、thisを渡すことはありません現在のスレッドへの影響が影響を受けていない限り、ステートメントを並べ替えることができます。 thisが別のスレッドで実行されているプロセスに渡された場合、並べ替えを行うと奇妙で微妙なバグが発生する可能性があります。

別の理由は、サブクラスが独自の初期化を提供する可能性があるため、クラスのコンストラクタの最後の行で構築が完了しないことがあります。

関連する問題