Singleton:スレッドセーフな実装
ダブルチェックロッキング、enum、holder パターンを使ってスレッドセーフな Singleton を構築します。
「Singleton:スレッドセーフな実装」はCoddyKit上の無料Java Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJava Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Java Academyコースには全4レッスンが含まれています。
シングルトンパターン
Singletonは、JVM内にクラスのインスタンスが1つだけ存在することを保証します。一般的な用途には、設定マネージャー、コネクションプール、ロギングサービスなどがあります。
素朴なSingleton — スレッドセーフではない
従来の遅延Singletonは、同時アクセス時に正しく動作しません。2つのスレッドが同時にnullチェックを通過し、2つのインスタンスを生成する可能性があります。
public class Config {
private static Config instance;
private Config() {}
public static Config getInstance() {
if (instance == null) { // race condition!
instance = new Config();
}
return instance;
}
}synchronizedメソッド — 単純だが低速
getInstance()にsynchronizedを追加するとスレッドセーフになりますが、インスタンスが存在した後も呼び出しのたびにロックするため、不要なオーバーヘッドが生じます。
public static synchronized Config getInstance() {
if (instance == null) instance = new Config();
return instance;
}ダブルチェックロッキング
ロックなしでチェックし、その後synchronizedブロック内でもう一度チェックします。命令の並べ替えを防ぐため、フィールドにvolatileが必要です。
public class Config {
private static volatile Config instance;
private Config() {}
public static Config getInstance() {
if (instance == null) {
synchronized (Config.class) {
if (instance == null) instance = new Config();
}
}
return instance;
}
}Initialization-on-Demand Holder
最も安全で効率的な遅延Singletonです。privateなstaticネストクラスでインスタンスを保持します。JVMはgetInstance()が初めて呼び出されたときだけこのクラスをロードするため、クラスのロード自体がスレッドセーフです。
public class Config {
private Config() {}
private static final class Holder {
static final Config INSTANCE = new Config();
}
public static Config getInstance() {
return Holder.INSTANCE;
}
}enumシングルトン
Effective Javaでは、定数を1つだけ持つenumが推奨されています。簡潔でスレッドセーフ、シリアライズにも安全で、リフレクション攻撃の影響も受けません。
public enum AppConfig {
INSTANCE;
private String apiUrl = "https://api.example.com";
public String getApiUrl() { return apiUrl; }
}
// Usage:
String url = AppConfig.INSTANCE.getApiUrl();即時初期化
起動時のコストが許容できる場合は、static finalフィールドを使ってクラスのロード時にインスタンスを初期化します。単純でスレッドセーフですが、使われない場合でも必ずインスタンスが生成されます。
public class Config {
private static final Config INSTANCE = new Config();
private Config() {}
public static Config getInstance() { return INSTANCE; }
}Singletonとシリアライズ
Singletonをシリアライズしてからデシリアライズすると、INSTANCEを返すreadResolve()を追加しない限り、新しいインスタンスが生成されます。enum方式なら、この問題に自動的に対処できます。
private Object readResolve() { return INSTANCE; }Singletonとリフレクション攻撃
リフレクションを使うとprivateコンストラクターを呼び出せます。すでにインスタンスが存在する場合はコンストラクターで例外をスローして対策してください。enumシングルトンはJVM仕様によってこの攻撃の影響を受けません。
private Config() {
if (Holder.INSTANCE != null) {
throw new IllegalStateException("Use getInstance()");
}
}依存性注入フレームワークでのSingleton
Springでは、デフォルトでBeanがSingletonになります(@Scope("singleton"))。Singletonパターンを手動で実装することはほとんどなく、DIコンテナに管理を任せます。
@Component // Spring manages a single instance
public class FeatureFlags {
private final boolean darkMode = true;
public boolean isDarkMode() { return darkMode; }
}Singletonのテスト
Singletonはグローバルな状態を持つため、単体テストが難しくなります。手動のSingleton実装より依存性注入を優先し、テストではコンストラクターインジェクションによってモックインスタンスを注入してください。
クイックチェック
Effective Javaで推奨されているSingletonの方式はどれですか。
まとめ
スレッドセーフなSingletonには、Initialization-on-Demand Holderまたはenum方式を使用してください。素朴な遅延初期化は避けます。Springアプリケーションでは、スコープ管理をフレームワークに任せてください。
よくある質問
「Singleton:スレッドセーフな実装」レッスンは無料ですか?
はい。「Singleton:スレッドセーフな実装」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Java Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Java Academyコースには全4レッスンが含まれています。
「Singleton:スレッドセーフな実装」で何を学びますか?
ダブルチェックロッキング、enum、holder パターンを使ってスレッドセーフな Singleton を構築します。 ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Java Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのJava Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。
「Singleton:スレッドセーフな実装」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このJava Academyレッスンでコードを書いて実行できますか?
はい。すべてのJava Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- Singleton:スレッドセーフな実装
- Factory Method パターン
- 製品ファミリーのための Abstract Factory
- Fluent API を使った Builder パターン