静的コードブロックを使用して、レジストリ内の一部のコントローラーを初期化しています。したがって、クラスが最初にロードされたときに、この静的コードブロックが絶対に一度だけ呼び出されることを保証できますか?このコードブロックがいつ呼び出されるかを保証することはできませんが、Classloaderが最初にロードするときに推測していることを理解しています。静的コードブロック内のクラスで同期できることに気付きましたが、私の推測では、これは実際に何が起こるのでしょうか?
簡単なコード例は次のとおりです。
class FooRegistry {
static {
//this code must only ever be called once
addController(new FooControllerImpl());
}
private static void addController(IFooController controller) {
// ...
}
}
または私はこれを行う必要があります。
class FooRegistry {
static {
synchronized(FooRegistry.class) {
addController(new FooControllerImpl());
}
}
private static void addController(IFooController controller) {
// ...
}
}
はい、Java静的初期化子はスレッドセーフです(最初のオプションを使用してください)。
ただし、コードが1回だけ実行されるようにする場合は、クラスが単一のクラスローダーによってのみロードされるようにする必要があります。静的初期化は、クラスローダーごとに1回実行されます。
これは、遅延初期化に使用できるトリックです
enum Singleton {
INSTANCE;
}
またはpre Java 5.0
class Singleton {
static class SingletonHolder {
static final Singleton INSTANCE = new Singleton();
}
public static Singleton instance() {
return SingletonHolder.INSTANCE;
}
}
SingletonHolderの静的ブロックはスレッドセーフな方法で1回実行されるため、他のロックは必要ありません。クラスSingletonHolderは、instance()を呼び出すときにのみロードされます
通常の状況では、静的初期化子のすべてがそのクラスを使用するすべての前に発生するため、通常は同期は必要ありません。ただし、このクラスは、静的なintiailiserが呼び出すすべてのものにアクセスできます(他の静的な初期化子を呼び出すことを含む)。
クラスはロードされたクラスによってロードできますが、必ずしもすぐに初期化される必要はありません。もちろん、クラスはクラスローダーの複数のインスタンスによってロードされ、それによって同じ名前を持つ複数のクラスになることができます。
はい、ある種の
static
初期化子は1回しか呼び出されないため、その定義によりスレッドセーフです。スレッドの競合を取得するために、static
初期化子を2回以上呼び出す必要があります。
とはいえ、static
イニシャライザーは他の多くの点で混乱を招きます。呼び出される順序は実際には指定されていません。 static
初期化子が互いに依存している2つのクラスがある場合、これは本当に混乱します。また、クラスを使用するが、static
初期化子が設定するものを使用しない場合、クラスローダーが静的初期化子を呼び出すことは保証されません。
最後に、同期するオブジェクトを覚えておいてください。私はこれが本当にあなたが求めているものではないことを理解していますが、あなたの質問がaddController()
スレッドセーフにする必要があるかどうかを本当に求めていないことを確認してください。
はい、静的初期化子は一度だけ実行されます。 詳細はこちらをご覧ください 。