この投稿では、積極的な初期化、二重チェック ロック、および 内部静的クラス アプローチ。シングルトンの整合性を確保する上で、final キーワードがなぜ有益なのかについても説明します。
シングルトンを使用する理由1 つのインスタンスが必要な場合に便利です。一般的な使用例には、ロギング、構成、接続プールなどの共有リソースの管理が含まれます。シングルトンは、クラスにアクセスする複数のリクエストが、新しいインスタンスを作成するのではなく、確実に同じインスタンスを共有するようにします。
1. 積極的な初期化: 最も単純なシングルトン
public final class Singleton { // Instance is created at class loading time private static final Singleton INSTANCE = new Singleton(); // Private constructor prevents instantiation from other classes private Singleton() {} public static Singleton getInstance() { return INSTANCE; } }Eager Initialization の長所と短所
長所:
短所:
いつ使用するか: シングルトン クラスが軽量で、アプリケーションの実行時に使用されることが確実な場合は、即時初期化が最適です。
遅延初期化 と呼ばれる) には、二重チェックされたロックがスレッドセーフなソリューションを提供します。最小限の同期を使用し、初めてアクセスしたときにのみインスタンスが作成されるようにします。
public final class Singleton { // Marked as final to prevent subclassing // volatile ensures visibility and prevents instruction reordering private static volatile Singleton instance; // Private constructor prevents instantiation from other classes private Singleton() {} public static Singleton getInstance() { if (instance == null) { // First check (no locking) synchronized (Singleton.class) { // Locking if (instance == null) { // Second check (with locking) instance = new Singleton(); } } } return instance; } }二重チェックロックが機能する理由
最初のチェック: 同期ブロックの外側の if (instance == null) チェックにより、getInstance() が呼び出されるたびにロックすることを回避できます。これにより、初期化後の将来の呼び出しに対して同期ブロックがバイパスされるため、パフォーマンスが向上します。
同期ブロック: インスタンスが null になると、同期ブロックに入ると、1 つのスレッドのみがシングルトン インスタンスを作成するようになります。このポイントに到達する他のスレッドは待機する必要があり、競合状態が防止されます。
2 番目のチェック: 同期ブロック内で、インスタンスを再度チェックして、現在のスレッドが待機している間に他のスレッドがインスタンスを初期化していないことを確認します。この二重チェックにより、シングルトン インスタンスが 1 つだけ作成されることが保証されます。
volatile キーワードは、命令の並べ替えを防ぐために、二重チェックされたロック パターンに不可欠です。これがないと、ステートメント instance = new Singleton(); になります。完全に初期化される前に他のスレッドに対して完了したように見える可能性があり、部分的に構築されたインスタンスが返されることになります。 volatile は、インスタンスが null でなくなると、完全に構築され、すべてのスレッドに表示されることを保証します。
ここでは、サブクラス化を防ぐために、final キーワードが使用されています。 Singleton クラスを Final としてマークすると、次の 2 つの主な利点があります。
サブクラス化の防止: クラスを Final にすることで、他のクラスがそのクラスを拡張できなくなります。これにより、サブクラス化により追加のインスタンスが生成され、シングルトン パターンが崩れる可能性があるため、シングルトン クラスのインスタンスは 1 つだけ存在できることが保証されます。
Signals Immutability: Final は、シングルトン クラスが不変であることを意図しており、拡張すべきではないことを他の開発者に明確に示すものとして機能します。これにより、コードの理解と保守が容易になります。
つまり、final はシングルトンの整合性を強化し、サブクラス化による予期せぬ動作を回避するのに役立ちます。
長所:
短所:
使用する場合: このパターンは、シングルトン クラスがリソースを大量に消費し、常に必要になるとは限らない場合、またはマルチスレッド環境でのパフォーマンスが懸念される場合に役立ちます。
遅延初期化に対する代替のスレッドセーフなアプローチは、内部静的クラス パターンです。これは、Java のクラスローディング メカニズムを利用して、明示的な同期を行わずに、必要な場合にのみシングルトン インスタンスを初期化します。
public final class Singleton { // Instance is created at class loading time private static final Singleton INSTANCE = new Singleton(); // Private constructor prevents instantiation from other classes private Singleton() {} public static Singleton getInstance() { return INSTANCE; } }
このパターンでは、SingletonHelper クラスは getInstance() が初めて呼び出されたときにのみロードされます。これにより INSTANCE の初期化がトリガーされ、同期されたブロックを必要とせずに遅延読み込みが保証されます。
長所:
短所:
いつ使用するか: クリーンで保守可能なコードによる遅延初期化が必要な場合は、内部静的クラス パターンを使用します。シンプルさとスレッドセーフのため、多くの場合、これが好まれる選択です。
Java でスレッドセーフなシングルトンを実装するための 3 つの一般的な方法を検討してきました。
それぞれのアプローチには長所があり、さまざまなシナリオに適しています。ご自身のプロジェクトで試してみて、どれが最適かを確認してください。ご希望のアプローチやご質問がございましたら、コメント欄でお知らせください。
コーディングを楽しんでください! ????
以上がシングルトンを壊さないでください! Java で % スレッドセーフにする方法は次のとおりですの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。