説明
二重チェックロックで遅延初期化する際、共有フィールドをvolatileで宣言しないと、別のスレッドが初期化途中のオブジェクトを観測する可能性があります。セキュリティ設定、認証状態、シングルトンのキャッシュなど、一貫性が重要なオブジェクトでは予測しにくい動作につながります。
想定される影響
- 初期化が完了していないセキュリティ状態の使用
- 認証や認可の不安定な判定
- 断続的な障害や再現しにくい並行処理の不具合
対処方法
- 共有フィールドをJavaでは
volatile、Kotlinでは@Volatileで宣言してください。 - 可能であれば、必要時に初期化するholder、enumによるシングルトン、依存性注入コンテナーを使ってください。
- セキュリティ状態を表すオブジェクトは不変にしてください。
例
変更前
java
private static Config instance;
public static Config getInstance() {
if (instance == null) {
synchronized (Config.class) {
if (instance == null) {
instance = new Config();
}
}
}
return instance;
}
変更後
java
private static volatile Config instance;
説明:
- 変更前:
volatileなしの二重チェックロックで初期化するため、初期化の結果が完全に見える前に別のスレッドがオブジェクトを観測するおそれがあります。 - 変更後: 同じ共有フィールドを
volatileで宣言します。取得メソッドの他の部分は変更前と同じです。