6

二重チェックのロックを使用するコードに出くわし続けていますが、なぜそれが使用されているのか、いまだに混乱しています。

私は最初、ダブルチェック ロックが壊れていることを知りませんでした。それを知ったとき、この疑問が拡大しました。そもそもなぜ人々はそれを使用するのでしょうか? コンペア&スワップの方がいいんじゃない?

if (field == null)
    Interlocked.CompareExchange(ref field, newValue, null);
return field;

(上記のコードは C# 用ですが、私の質問は C# と Java の両方に当てはまります。)

二重チェックのロックには、アトミック操作と比較して、ある種の固有の利点がありますか?

4

5 に答える 5

12

二重チェックのロックには、アトミック操作と比較して、ある種の固有の利点がありますか?

(この回答は C# のみを対象としています。Java のメモリ モデルがどのようなものかはわかりません。)

主な違いは潜在的なレースです。あなたが持っている場合:

if (f == null)
    CompareExchange(ref f, FetchNewValue(), null)

FetchNewValue() は、異なるスレッドで任意に何度でも呼び出すことができます。それらのスレッドの 1 つがレースに勝ちます。FetchNewValue() が非常に高価で、一度だけ呼び出されるようにしたい場合は、次のようにします。

if (f == null)
    lock(whatever)
        if (f == null)
            f = FetchNewValue();

FetchNewValue が 1 回だけ呼び出されることを保証します。

私が個人的に低ロック遅延初期化を行いたい場合は、あなたが提案することを行います。インターロック操作を使用し、2 つのスレッドの両方がイニシャライザーを実行し、1 つだけが勝つというまれな競合状態に耐えます。それが受け入れられない場合は、ロックを使用します。

于 2011-05-23T15:44:00.360 に答える
4

C# では壊れたことがないので、今のところ無視できます。

あなたが投稿したコードは、 newValue がすでに利用可能であるか、または(再)計算するのが簡単であると想定しています。ダブルチェック ロックでは、実際に初期化を実行するスレッドは 1 つだけであることが保証されます。

そうは言っても、最近の C# では、通常は a を使用Lazy<T>して初期化を処理することを好みます。

于 2011-05-23T04:27:09.573 に答える
1

ダブルチェック ロックは、メソッド全体をロックするときに発生するパフォーマンスの低下が著しい場合に使用されます。つまり、(メソッドが呼び出される) オブジェクトまたはクラスを同期したくない場合は、ダブルチェック ロックを使用できます。

これは、ロックの競合が多く、ロックによって保護されたリソースの作成にコストがかかる場合に当てはまります。必要になるまで作成プロセスを延期したいと考えています。ダブル チェック ロックは、最初に条件 (ロック ヒント) を検証して、ロックを取得する必要があるかどうかを判断することにより、パフォーマンスを向上させます。

Java 5 で新しいメモリ モデルが導入されるまで、Java ではダブル チェック ロックが壊れていました。それまでは、あるスレッドではロック ヒントが true になり、別のスレッドでは false になる可能性が十分にありました。いずれにせよ、Initialization-on-Demand-Holderイディオムは、ダブルチェック ロック パターンの適切な代替手段です。これはとても理解しやすいと思います。

于 2011-05-23T04:33:09.213 に答える
0

私の頭に浮かぶ唯一の利点は、パフォーマンス (の錯覚) です。非スレッドセーフな方法でチェックしてから、変数をチェックするためにいくつかのロック操作を実行しますが、これにはコストがかかる可能性があります。ただし、二重チェックのロックは、スレッドセーフではないチェックからの確固たる結論を排除する方法で壊れており、とにかく時期尚早の最適化を常に私に叩きつけたので、私はノーと主張します-それは時代遅れの事前です- Java 時代のイディオムですが、修正を希望します。

編集:明確にするために、ダブルチェックロックは、毎回ロックとチェックのパフォーマンス向上として進化したイディオムであり、大まかに言えば、カプセル化されていないコンペアアンドスワップと同じものに近いと思います. 個人的には、コードの同期セクションをカプセル化することも好きなので、汚い仕事をするために別の操作を呼び出すほうがよいと思います。

于 2011-05-23T04:16:17.940 に答える
0

起動時にのみ変更される値にアクセスするためにロックする必要がないことは、あるレベルでは「理にかなっています」スレッドは起動時にアクセスしようとし、ほとんどの場合は機能します。壊れていますが、なぜ簡単に陥りやすいのかがわかります。

于 2011-05-23T04:25:49.397 に答える