次の記事は、WeChatパブリック アカウントXiaoha Learn Java 、著者AllenJiangによるものです。
シングルトンパターンは、23種類のGOF(デザインパターン)の中で最もシンプルなデザインパターンであり、最もクラシックなデザインパターンです。Javaインタビューでは、それは必要な知識ポイントであると言えます。次に、それについて詳しく説明しましょう。
インタビュアー:あなたはデザインパターンに精通していますか?作品で使用したデザインパターンは何ですか?
応募者:シングルトンモード、ファクトリモード、責任の連鎖モード、仕事で一般的に使用される代理店モードがあります...
インタビュアー:ああ!シングルトンパターンについて説明しましたが、シングルトンパターンは何と言えますか?シングルトンモードを使用する理由いくつかのシングルトンモードがありますか?使用する際の注意点は?
一般的に、インタビュアーは、上記の対話を通じてシングルトンモードの知識ポイントに切り込みます。
シングルトンパターンとは何ですか?
簡単に言うと、単一列モードは、プログラムの存続期間中、メモリ内にオブジェクトのインスタンスが1つだけ存在することを保証することです。つまり、クラスのオブジェクトは1つだけです。
シングルトンモードを使用する理由
シングルトンモードを使用することは、コードの実行パフォーマンスを向上させることに他なりません。次の2つの点について説明できます。
-
1.メモリリソースを節約する
-
2.時間の節約(オブジェクトを割り当てる時間)
1つ目は、メモリリソースを節約することです。プログラム内の一部の大きなオブジェクトでは、これらのオブジェクトが大量のメモリを占有します。頻繁に作成すると、メモリのオーバーヘッドが増加するだけでなく、メモリ割り当て時間が大量に消費されます。さらに、GC(ガベージコレクション)、GCが頻繁にトリガーされます。時間のオーバーヘッドが増加します深刻なケースでは、フルGCも発生し、プログラムのメインスレッドがブロックされる可能性があります。このような状況の中で、単列モデルが誕生しました。
いくつかのシングルトンパターンはありますか?
通常は5種類で十分ですが、幅広い知識を示すために次のように言うことができます。
候補:細分化されたシングルトンモデルには7種類ありますが、厳密には5種類しかありません。7つのサブディビジョンについてお話ししましょう。
1つ目:遅延、安全でないスレッド
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();}
return instance;
}
}
この書き込みメソッドは遅延読み込みですが、致命的なのは、マルチスレッドの場合、インスタンス化されたシングルトンオブジェクトのインスタンスが複数存在することです。
2番目の種類:遅延、スレッドセーフ
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();}
return instance;
}
}
この書き込み方法はマルチスレッド環境で適切に機能し、遅延読み込みの利点もありますが、残念ながら効率は非常に低く、99%のケースでは同期は必要ありません。
3番目のタイプ:空腹の中国人
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
このメソッドは、Javaクラスのロードメカニズムに基づいてマルチスレッド同期の問題を回避しますが、そのため、インスタンスはロード時にインスタンス化され、インスタンス化には多くの理由があります。インスタンス化されました。また、インスタンス化のほとんどのシングルトンモードは、遅延読み込みの設計に違反するgetInstance()メソッドを呼び出すことです。
注1:インタビュアーは、次のことを尋ねることもあります。インスタンスはいつ初期化されますか?
インスタンスは、クラスがロードされるときに初期化されます。クラスのロードに関しては、クラスをロードする特定の時間にJVM仮想マシン仕様に必須の制約はありませんが、クラスの初期化に関して、仮想マシンは厳密に以下を規定します次の4つのバイトコードが指定されている場合、それぞれ4つの状況があります。
-
1. 新しい
-
2. getStatic
-
3. putStatic
-
4. invokeStatic
上記の4バイト指定コードに遭遇したときに、クラスが初期化されていない場合は、最初にその初期化をトリガーする必要があります。
上記の4つの命令を生成するタイミングは、次のシナリオに対応しています。
-
1. new キーワードを使用して、新しい命令に対応するオブジェクト==>をインスタンス化します。
-
2.クラスの静的フィールドを読み取ります(finalによって変更された静的フィールドを除き、結果をコンパイル時に定数プールに入れます)==> getStatic命令に対応します。
-
3.クラスの静的フィールドを設定します(finalによって変更された静的フィールドを除き、結果をコンパイル時に定数プールに入れます)==> putStatic命令に対応します。
-
4. invokeStatic命令に対応するクラス==>の静的メソッドを呼び出します。
注2:インタビュアーは、JVMクラスのロードメカニズムも尋ねるかもしれません。
この時点では、クラスローダーの親の委任モデルについて説明できますが、ここでは説明しません。
4番目のタイプ:空腹な男、バリアント
public class Singleton {
private Singleton instance = null;
static {
instance = new Singleton();
}
private Singleton (){}
public static Singleton getInstance() {
return this.instance;
}
}
ここでは、静的ブロックを使用してオブジェクトをインスタンス化しています。これは、実際には3番目のブロックと同様です。
5番目:静的内部クラス
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
このメソッドはまた、クラスローダーメカニズムを使用して、インスタンスの初期化時にスレッドが1つだけであることを確認します。これは、3番目および4番目のメソッドとは異なります(わずかな違い):3番目および4番目のメソッドは、シングルトンクラスと同じ長さです。ロードされている場合、インスタンスはインスタンス化され(遅延ロード効果なし)、このようにして、Singletonクラスがロードされ、インスタンスが初期化されない可能性があります。SingletonHolderクラスはアクティブに使用されないため、getInstanceメソッドが呼び出されたことが示されている場合にのみ、SingletonHolderクラスが表示され、インスタンスがインスタンス化されます。インスタンスをインスタンス化してリソースを消費する場合、ロードを遅らせたいと想像してください。一方、シングルトンクラスがロードされたときにインスタンス化したくないのは、シングルトンクラスが他の場所でアクティブに使用されることを保証できないためです。が読み込まれている場合、現時点でインスタンスをインスタンス化することは明らかに不適切です。現時点では、この方法は3番目と4番目の方法に比べてかなり合理的です。
第6:列挙
public enum Singleton {
INSTANCE;
public void whateverMethod(){}
}
このメソッドは、「Effective Java」Josh Blochの作者によって提唱されています。マルチスレッド同期の問題を回避するだけでなく、シリアル化/逆シリアル化攻撃およびリフレクション攻撃も自動的に回避します(リフレクションによって列挙クラスを生成することはできません)。
第7:ダブルチェックロック(DCL)
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();}
}
}
return singleton;
}
}
これは、2番目の方法のアップグレードバージョンであり、一般にダブルチェックロックと呼ばれます。同期の外側に判断のレイヤーを追加することにより、オブジェクトが作成されると同期ブロックに入ることができなくなります。このスキームは、ロックの粒度を削減するだけでなく、スレッドの安全性を保証するだけでなく、パフォーマンスを大幅に向上させます。
同時に、JVM命令の再配置を防ぐために、キーワードvolidateの役割についても説明する必要があります詳細については、他の記事「知っておくべき揮発性キーワード」を参照してください。
まとめ
しかし、一般的に言って、第1の種類は単一のケースではなく、第4の種類と第3の種類は1種類です。カウントすると、第5の種類は別々に書くことができます。したがって、一般的な単一のケースは5つの方法で記述されます。
-
1.怠惰な男
-
2.空腹の男
-
3.ダブルチェックロック(DCL)
-
4.列挙
-
5.静的内部クラス
-