シングルトンが次のように実装されている場合、
class Singleton {
private static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
}
この実装は遅延初期化アプローチとどのように異なりますか?この場合、インスタンスは、クラスが読み込まれたときに作成され、クラス自体が最初にアクティブに使用されたときにのみ読み込まれます(たとえば、Singleton singleton = nullを宣言した場合は、Singleton.getInstance()は読み込まれません)。
遅延初期化アプローチでも、インスタンスはgetInstance()の呼び出しで作成されます
ここで何か不足していますか?
シングルトンインスタンスをロードするには、他の静的メソッドまたは静的メンバー変数も呼び出すことができます。
class Logger {
private static Logger instance = new Logger();
public static String LOG_LINE_SEPERATOR =
System.getProperty("line.separator");
public static Logger getInstance() {
return instance;
}
public static String logPattern() {
return null;
}
}
...
Logger.LOG_LINE_SEPERATOR; // load Logger instance or
Logger.logPattern(); // load Logger instance
遅延初期化では、クラスが読み込まれたときではなく、必要なときにのみインスタンスを作成します。したがって、不要なオブジェクトの作成を回避できます。とはいえ、他にも考慮すべきことがあると言われています。遅延初期化では、インスタンスを取得するためのパブリックAPIを提供します。マルチスレッド環境では、不要なオブジェクトの作成を回避することが課題となります。すでに作成されたオブジェクトをチェックするために不要なロックを行う同期ブロックを配置します。したがって、この場合はパフォーマンスの問題になります。
そのため、オブジェクトの作成が重要なメモリを消費せず、ほとんど常にアプリケーションで使用される場合は、静的初期化で作成するとよいでしょう。また、この場合はインスタンスをfinalにすることを忘れないでください。これにより、オブジェクトの作成が適切に反映され、マルチスレッド環境で重要なメインメモリ全体に反映されます。
これを参照してください チュートリアル シングルトン+遅延読み込み+マルチスレッド環境のケースでIBMから
=============== 2018年9月9日に編集====================
また、オブジェクト作成オンデマンドパターン here も確認する必要があります。
あなたが言及する理由のために、これはと同じことをするためのより複雑な方法です
enum Singleton {
INSTANCE;
}
遅延初期化の使用は、クラスが初期化される可能性があるが、その時点でシングルトンをロードしたくない場合にのみ役立ちます。ほとんどの場合、これはやりすぎです。
注:クラスを参照するだけではクラスは初期化されません。
例えばある条件が設定されるまで開始できない、不適切に記述されたクラスがあるとします。この場合、n
はゼロ以外でなければなりません。
public class Main {
public static void main(String ... args) {
Class c= LazyLoaded.class;
System.out.println(c);
}
static class LazyLoaded {
static int n = 0;
static {
System.out.println("Inverse "+1000/n);
}
}
}
プリント
class Main$LazyLoaded
まず、シングルトンパターンが過剰に使用されています。 「何かの1つ」が必要な場合に本当に実行したいことは、選択したDIフレームワークでシングルトンを宣言することです。これは事実上、設定駆動型の熱心なシングルトンであり、モックを注入して適切なテストを行うためのオプションを解放します。
なぜ遅延ロードしないのですか?クラスの大規模な初期化ルーチンが構築されていない限り(これはアンチパターンでもあると私は主張します)、遅延読み込みには利点がなく、多くの欠点があります。複雑さが増すだけで、プログラムが正しく実行されない場合はプログラムが壊れる可能性があります。正しい方法(必要な場合)は、初期化オンデマンドホルダーイディオムを使用することです。
シングルトンインスタンスの遅延読み込みでは、次のように使用しています。
class Singleton {
private static Singleton instance;
private Singleton(){
}
public static Singleton getInstance() {
if(null==instance){
synchronized(Singleton.class){
if(null==instance){
instance = new Singleton();
}
}
}
return instance;
}
}
シングルトンデザインパターンでのEagerの読み込みは、アプリケーションの起動時にオンデマンドではなくシングルトンオブジェクトを初期化し、将来使用するためにメモリに準備しておく必要があるプロセスではありません。シングルトンデザインパターンでEager Loadingを使用する利点は、CLR(共通言語ランタイム)がオブジェクトの初期化とスレッドセーフを処理することです。つまり、マルチスレッド環境のスレッドセーフティを処理するためにコードを明示的に記述する必要はありません。
遅延読み込みまたは遅延読み込みは設計パターンですが、オブジェクトの初期化を必要な時点まで遅らせるために一般的に使用されている概念と言えます。したがって、遅延読み込みの主な目的は、オンデマンドでオブジェクトを読み込むことです。必要に応じてオブジェクトと言うこともできます。注意すべき最も重要な点は、オブジェクト作成のコストが非常に高く、そのオブジェクトの使用が非常に少ない場合は、遅延ロードを使用する必要があるということです。遅延読み込みを適切に使用すると、アプリケーションのパフォーマンスが向上します。
次のドットネットチュートリアルを参照して、両方の明確な例を見つけてください。
https://dotnettutorials.net/lesson/lazy-vs-eager-loading-chsrap/