ProgrammingJavaバックエンド開発者

Javaでは、マルチスレッドおよびシリアル化を考慮してSingletonパターンを実装するにはどうすればよいですか?実装にはどのような注意点がありますか?

Hintsage AIアシスタントで面接を突破

回答

クラシックなSingletonは、オブジェクトのインスタンスが1つだけ作成されることを保証します。Javaにはいくつかの実装方法がありますが、マルチスレッドおよびシリアル化を考慮する場合、次のような注意点があります。

  1. スレッドセーフな実装(ダブルチェックロック): 遅延初期化によく使われます。
public class Singleton { private static volatile Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
  1. Enum Singleton: シリアル化、リフレクション、マルチスレッドからの保護の観点から最良の方法です。
enum EnumSingleton { INSTANCE; // メソッド }
  1. シリアル化の問題: 通常のSingletonは、シリアル化/デシリアル化後にインスタンスの一意性を失う可能性があります。正しく機能させるためには、readResolve()メソッドを追加する必要があります:
private Object readResolve() { return getInstance(); }

トリックの質問

スレッドセーフなSingletonのために、メソッドgetInstance()にsynchronizedを使用するだけで十分ですか?

回答: はいですが、そのアプローチはパフォーマンスを低下させます。なぜなら、synchronizedはgetInstanceへの各呼び出しで呼び出されるからです。より効率的なのは、Double-checked Locking + volatileを使うか、Enumを使用してSingletonを実装することです。

非効率的なコードの例:

public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; }

物語

金融システムでSingletonを実装する際に、ダブルチェックロックのinstanceへの参照にvolatileを追加することを忘れました。その結果、高負荷時にクラスの二重インスタンス生成が発生し、報告の一貫性が失われました。


物語

ロギングライブラリでは、プライベートな静的オブジェクトを通じてSingletonを実装しましたが、シリアル化およびその後のデシリアル化(例えば、クラスター環境で)で複数のインスタンスが発生しました。問題はreadResolve()を追加することで解決されました。


物語

分析システムで、開発者はsynchronizedメソッドgetInstance()を通じてスレッドセーフなSingletonを実装しました。高負荷システムでピークトラフィックが発生したとき、パフォーマンスが急激に低下し、getInstance()の呼び出し(1秒間に数千回)が不必要な同期のために互いにブロックされていることが判明しました。初期化は1回だけ必要です。