ホームページ >Java >&#&チュートリアル >Java シングルトン モードで Hungry Man パターンと Lazy Man パターンを実装する方法の詳細な説明
複数のインスタンスを作成するのではなく、プログラム内に特定のクラスのインスタンスが 1 つだけ存在するようにすると、効率が向上します。
単一インタレスト モードでは、通常、インスタンス オブジェクトを取得するために getInstance() メソッドが 1 つだけ提供され、setInstance() メソッドは提供されません。これは、他のインスタンス オブジェクトのインスタンス化を避けるためです。
シングルトン モードには 2 つのモードがあります。1 つはハングリーマン モード、もう 1 つは怠け者モードです。
ハングリー ハン モードとは、クラスがロードされるとすぐにインスタンス化され、以降の使用でのみ表示されます。
package thread.example; //饿汉模式 public class HungrySingle { //在类加载的时候就实例化了,类加载只有一次,所以值实例化出了一份该实例对象 private static HungrySingle instance = new HungrySingle(); public static HungrySingle getInstance() { return instance; } }
クラスがロードされたときにすでにインスタンス化されているため、インスタンス化は行われませんインスタンス化された変更操作は読み取り操作のみです。マルチスレッド状況ではスレッドセーフです。
は、クラスがロードされたときに直接インスタンス化されませんが、指定されたインスタンス メソッドが呼び出されたときにインスタンス化されます。 , これにより、使用したくないときにインスタンス化されなくなります。一般的に言えば、Hungry Man モードよりも効率的です。
package thread.example; //单线程的懒汉模式 public class LazySingle { private static LazySingle instance = null; //只有在调用该方法的时候才实例化 public static LazySingle getInstance() { if(instance == null) { instance = new LazySingle(); } return instance; } }
(1) マルチスレッド環境での遅延モードの不整合の原因となります。状況 セキュリティ上の理由
マルチスレッドの場合、両方のスレッドが、instance=null のコピーを取得する可能性があります。これは、スレッド 1 が自身の郡のインスタンスを変更する場合、スレッド 1 がインスタンスを変更する時間がないためです。これにより、スレッド 2 もインスタンス オブジェクトをインスタンス化し、この時点ではシングルトン モードではなくなります。この問題の主な原因は、インスタンスの変更によってアトミック性が失われることにありますが、アトミック性を確保するために、スレッドセーフを実現するためのロックを考えました。
(2) 解決策コード例
バージョン 1
package thread.example; //多线程安全下的懒汉模式 public class LazySingle { private LazySingle() { } private static LazySingle instance = null; //只有在调用该方法的时候才实例化 public static synchronized LazySingle getInstance() { if (instance == null) { instance = new LazySingle(); } return instance; } }
バージョン 1 のコードはスレッド セーフを保証しますが、メソッドが呼び出されるたびにロックが発生します。ロック解除の問題をさらに最適化するために、ロックの粒度を減らして効率を向上させることができます。ロックを追加すると、高い同時実行性を達成できなくなるためですが、それでも効率を向上させたいので、それを最適化します。
バージョン 2
Double if 判定ロックにより効率が向上
package thread.example; public class SecurityLazyModle { private LazySingle() { } private static volatile SecurityLazyModle instance = null;//保证内存可见性,防止编译器过度优化(指令重排序) public static SecurityLazyModle getInstance() { if(instance == null) { synchronized (SecurityLazyModle.class) { if(instance == null) { instance = new SecurityLazyModle(); } } } return instance; } }
バージョン 2 の説明
if の最初の層は、現在の状態かどうかを判断することです。インスタンスが作成されると、同期の 2 番目のレベルは、現在の if に入るスレッドがロックを競合できるようにすることです。ロックを取得したスレッドが if の 3 番目のレベルに入ると、そのスレッドが空であるかどうかが判断されます。空の場合、オブジェクトをインスタンス化してから解放します。ロックの場合、ロックが解放された後、インスタンスは空ではなくなり、後続のスレッドは 3 番目の層でブロックされます。後で getInstance() メソッドにアクセスすると、それが見つかります。インスタンスはもう空ではないため、プリエンプトする必要はありません。競合するロックも多くの時間を消費するため、リソースをロックします。このように処理することで、スレッドの安全性が確保され、効率が向上します。
#ここで volatile を使用する目的は、コンパイラの最適化によって引き起こされる命令の並べ替えを防ぐことです。新しいオブジェクトの実行はアトミックな操作ではなく、次の 3 つのステップに分けることができます:
1. メモリ領域の割り当て
2. オブジェクトのインスタンス化
以上がJava シングルトン モードで Hungry Man パターンと Lazy Man パターンを実装する方法の詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。