Java シングルトン モードの違い: 1. 腹を空かせた人のクラスがロードされると、シングルトンの初期化が完了します。シングルトンはすでに存在しますが、怠け者は getInstance を呼び出したときにこれを初期化するために戻るだけです。 Singleton; 2. ハングリー スタイルは本質的にスレッド セーフですが、lazy スタイル自体はスレッド セーフではありません。
[関連する学習の推奨事項: Java 基本チュートリアル]
Java シングルトン モードの違いはい:
1. 遅延シングルトン
//懒汉式单例类.在第一次调用的时候实例化自己 public class Singleton { private Singleton() {} private static Singleton single=null; //静态工厂方法 public static Singleton getInstance() { if (single == null) { single = new Singleton(); } return single; } }
シングルトンは、コンストラクターをプライベートに制限することで、クラスが外部からアクセスされるのを回避します。同じ仮想マシンのスコープ内では、Singleton の唯一のインスタンスには getInstance() メソッドを介してのみアクセスできます。
(実際、Java リフレクション メカニズムを通じて、プライベート コンストラクターを使用してクラスをインスタンス化することができます。これにより、基本的にすべての Java シングルトン実装が無効になります。この問題についてはここでは説明しません。
ただし、上記の遅延スタイルのシングルトン実装では、スレッド セーフティの問題が考慮されていません。スレッドは安全ではありません。複数のシングルトン インスタンスが出現する可能性があります。並行環境でスレッド セーフを実現するには、次の 3 つのメソッドがあり、これらはすべて getInstance メソッドを変更して、遅延スタイル シングルトンのスレッド セーフを確保します。スレッド セーフについてあまり詳しくない場合は、最初に次の 3 つのヒントをスキップしてください。記事、ハングリー スタイルのシングルトンを見て、それを読んだ後に戻ってスレッド セーフの問題を検討してください:
1. getInstance メソッドに同期を追加します
public static synchronized Singleton getInstance() { if (single == null) { single = new Singleton(); } return single; }
2. ロックを再確認します
public static Singleton getInstance() { if (singleton == null) { synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } } return singleton; }
3. 静的内部クラス
public class Singleton { private static class LazyHolder { private static final Singleton INSTANCE = new Singleton(); } private Singleton (){} public static final Singleton getInstance() { return LazyHolder.INSTANCE; } }
これは、上記の 1 および 2 よりも優れています。スレッド セーフを実現するだけでなく、スレッドの安全性も回避します。同期によるパフォーマンスへの影響。
2. Hungry Han Style シングルトン
//饿汉式单例类.在类初始化时,已经自行实例化 public class Singleton1 { private Singleton1() {} private static final Singleton1 single = new Singleton1(); //静态工厂方法 public static Singleton1 getInstance() { return single; } }
Hungry Han Style は、クラスの作成時にシステムで使用する静的オブジェクトをすでに作成しており、クラス作成時にそれを変更しません。したがって、本質的にスレッドセーフです。
3. 登録されたシングルトン (無視できます)
//类似Spring里面的方法,将类名注册,下次从里面直接获取。 public class Singleton3 { private static Map<String,Singleton3> map = new HashMap<String,Singleton3>(); static{ Singleton3 single = new Singleton3(); map.put(single.getClass().getName(), single); } //保护的默认构造子 protected Singleton3(){} //静态工厂方法,返还此类惟一的实例 public static Singleton3 getInstance(String name) { if(name == null) { name = Singleton3.class.getName(); System.out.println("name == null"+"--->name="+name); } if(map.get(name) == null) { try { map.put(name, (Singleton3) Class.forName(name).newInstance()); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } return map.get(name); } //一个示意性的商业方法 public String about() { return "Hello, I am RegSingleton."; } public static void main(String[] args) { Singleton3 single3 = Singleton3.getInstance(null); System.out.println(single3.about()); } }
登録されたシングルトンは、実際にはシングルトン クラスのインスタンスのセットを維持し、これらのインスタンスをマップ内に格納します (登録簿)、登録されている場合はマップから直接返されますが、登録されていない場合は登録されてから返されます。
ここでは、登録スタイルのシングルトンを無視できるものとしてマークしました。私の理解によると、まず第一に、これは使用頻度が低いです。さらに、静的メソッドのため、内部実装では依然として Hungry スタイルのシングルトンが使用されていますブロック内にある場合、クラスがロードされるときにそのシングルトンがインスタンス化されます。
4. Hungry Man スタイルと Lazy Man スタイルの違い
Hungry Man と Lazy Man の名前で言えば、
ハングリー ハンとは、クラスがロードされると、getInstance が呼び出されたときにシングルトンがすでに存在していることを確認するためにシングルトンが初期化されることを意味します。
怠惰な人は怠惰で、シングルトンの初期化に戻るだけです。 getInstance が呼び出されたとき。
さらに、次の 2 つの点で次の 2 つのメソッドを区別できます:
1. スレッド セーフ:
Hungry Chinese style は本質的にスレッド セーフ。問題なくマルチスレッドに直接使用できます。
遅延スタイル自体はスレッド セーフではありません。スレッド セーフを実現するために、いくつかの記述方法があります。1、2、これら 3 つの実装には、リソースの読み込みとパフォーマンスにいくつかの違いがあります。
2. リソースの読み込みとパフォーマンス:
Hungry Chinese スタイルは、クラスの作成時に静的オブジェクトをインスタンス化します。このシングルトンが後で使用されるかどうかに関係なく、一定量のメモリを占有します。 . ですが、それに応じて、リソースが初期化されているため、初めて呼び出されたときの速度は速くなります (
および遅延スタイルは、名前が示すように、読み込みを遅らせ、読み込みだけを行います)シングルトンが初めて使用されるときに実行されます。オブジェクトは、初めて呼び出されたときにインスタンス化され、初期化されます。実行する作業が多い場合は、パフォーマンスに多少の遅延が発生します。お腹を空かせた中華風と同じです。
3 つの実装 1、2、および 3 については、いくつかの違いがあります。
最初のタイプは、メソッド呼び出しに同期を追加します。スレッド セーフではありますが、毎回同期する必要があります。時間に影響します。パフォーマンスに影響します。結局のところ、99% の場合、同期は必要ありません。
2 番目のタイプは、getInstance で 2 つの null チェックを実行し、シングルトンが呼び出されたときにのみ実行されるようにすることです。同期、これもスレッドセーフであり、毎回の同期によるパフォーマンスの損失を回避します
3 番目の方法では、クラスローダー メカニズムを使用して、インスタンスの初期化時にスレッドが 1 つだけであることを確認します。スレッドセーフでもあり、パフォーマンスの低下もないので、通常はこれを使用することが多いです。
関連する学習に関する推奨事項: プログラミング ビデオ
以上がJava シングルトン パターンの違いは何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。