ここには多くの良いデータがありますが、さらに情報を追加したいと思いました。
スレッド間で共有されるオブジェクトを構築するときは、オブジェクトへの参照が時期尚早に「リーク」しないように十分注意してください。
オブジェクトを作成している間は、完全に作成する前に他のスレッドがこのオブジェクトにアクセスできないようにする必要があります。つまり、コンストラクターでは、次のようにすべきではありません。
static
他のスレッドからアクセスできるクラスのフィールドにオブジェクトを割り当てます。
- 完全に初期化される前に、オブジェクトのフィールドの使用を開始する可能性があるコンストラクターでオブジェクトのスレッドを開始します。
- オブジェクトをコレクションにパブリッシュするか、他のスレッドがオブジェクトを完全に構築する前に参照できるようにするその他のメカニズムを介してパブリッシュします。
次の行をコンストラクターに追加したくなるかもしれません。
instances.add(this);
したがって、次のようなものは不適切です。
public class Foo {
// multiple threads can use this
public static List<Foo> instances = new ArrayList<Foo>();
public Foo() {
...
// this "leaks" this, publishing it to other threads
instances.add(this);
...
// other initialization stuff
}
...
さらに複雑なのは、Java コンパイラー/オプティマイザーには、コンストラクター内の命令を並べ替えて、後で実行できるようにする機能があることです。これはinstances.add(this);
、コンストラクターの最後の行として実行しても、コンストラクターが実際に終了したことを確認するには不十分であることを意味します。
複数のスレッドがこのパブリッシュされたオブジェクトにアクセスする場合は、synchronized
. 心配する必要のない唯一のフィールドはfinal
、コンストラクターが終了したときに構築が完了することが保証されているフィールドです。 volatile
フィールド自体が同期されるため、心配する必要はありません。