JetBrains Rider 2024.1 ヘルプ

コード検査: ダブルチェックロックパターンの誤った実装の可能性: チェックされたフィールドへの読み取りアクセス。

次のコードを考えてみましょう。

public class Foo { private static volatile Foo _instance; private static readonly object Padlock = new object(); public static Foo GetValue() { if (_instance != null) return _instance; lock (Padlock) { if (_instance != null) return _instance; _instance = new Foo(); _instance.Init(); } return _instance; } private void Init() { // object initialization } }

Init()Foo の状態を初期化するために使用される方法であると仮定すると、上記のコードはマルチスレッド環境では期待通りに機能しない可能性があります。

1 つのスレッドが _instance = new Foo(); を実行したがまだ _instance.Init(); を実行していない場合があります。この時点で他のスレッドが GetValue() を呼び出すと、メソッドは _instance が null ではないことを確認し、初期化されていないインスタンスが呼び出し元に返されます。

上記のコードでこの問題を解決するには、2 つの方法があります。

最初の、最も明白なことは、Init() の内容をプライベートコンストラクターに移動することです。

2 つ目は、チェックされていない変数で初期化を実行してから、チェックされた変数に割り当てることです。これにより、問題が解消されます。このようにして _instance はすでに初期化されているときだけ null にはなりません。上記の例の lock ステートメントのコードは、次のように書き直すことができます。

if (_instance != null) return _instance; var temp = new Foo(); temp.Init(); _instance = temp;

StackOverflow に関するこの回答(英語)は、このパターンに関する他の考えられる問題と、なぜ _instancevolatile と宣言すべきかを説明します。