0

私は並行性に関しては初心者であり、問​​題を発見するときに自信がありません。かなり確立されたコードベースを調べていて、データ競合の影響を受けやすいと思われる次のコード (簡潔にするために編集) を見つけました。

public class Example extends Thread {
    boolean condition = false;

    public void run () {
        while (true) {
            synchronized (this) {
                try {
                    while( condition ) wait();
                }
                catch (InterruptedException e) { /*for brevity*/  }
            }

            // non-blocking computation
        }
    }

    public void setTrue () { condition = true; }

    public void setFalse () {
        synchronized (this) {
            condition = false;
            this.notifyAll();
        }
    }
}

私が理解している限りcondition、同期ブロックを使用してもコンパイラはメモリバリアを発行しないため、揮発性でなければなりません。それがコンパイラーの揮発性ストアconditionである場合は、setTrueStoreEnter.

上記がデータ競合の影響を受けやすいと信じるのは正しいですか? もしそうなら、どうすれば例を通してデータ競合を目撃できますか (単に JMM によって提供される保証を知るのではなく)。スレッドがループ内でランダムに呼び出す単純なテストでsetTrueは、データ競合は明らかになりません。

また、確認する条件が 1 つあり、それを待機するスレッドは 1 つだけなので、ここでの notifyAll の使用はやり過ぎだと思います。

ありがとうございました。

4

2 に答える 2

3

私が理解している限り、同期ブロックがあっても、コンパイラはメモリバリアを発行しないため、条件は揮発性でなければなりません。setTrue で条件付けする揮発性ストアの場合、コンパイラは StoreEnter を発行します。

それは正しくありません。ブロック内で共有変数を使用するとsynchronized、コードは同じロックで同じ変数を使用する他のスレッドに対してスレッドセーフになります。メモリ バリアが必要な場合は、それらが使用されます。

ただし、メソッドがブロックの外側でフラグを更新しているため、表示されたコードは正しくありません。setTrue()synchronized


上記がデータ競合の影響を受けやすいと信じるのは正しいですか?

うん…ちょっと。シナリオは次のとおりです。

  1. 状態はfalseです。
  2. setTrue条件変数をtrueキャッシュに設定する他のスレッド呼び出し。しかし、このsetTrueメソッドは を使用しないためsynchronized、書き込みバリアはなく、メイン メモリへのフラッシュもありません。
  3. 「サンプル」スレッドは、コミットされた最新の値をメイン メモリ (まだfalse) からフェッチし、想定どおりに待機しません。

また、確認する条件が 1 つあり、それを待機するスレッドは 1 つだけなので、ここでの notifyAll の使用はやり過ぎだと思います。

notify()それがあなたが意味するものであれば、...に置き換えることができます。しかし、正直なところ、どちらの種類の通知を使用しても実際の違いはありません。


あなたのコメント:

つまり、コンパイラは、この状況でメモリ バリアを送信する必要があるとは見なさないということです。

多分。ただし、「monitorenter」および「monitorexit」命令には暗黙的にメモリ バリアが含まれます。

と:

状態が揮発性であれば、それも正しいのではないでしょうか?

volatileANDの使用について話している場合synchronized、はい、それは正しいでしょう...ただし、冗長になります(バグが修正されvolatileていると仮定します)。setTrue

あなたが話しているvolatileだけなら、いいえ。だけでは効率的な「条件変数の待機」を実装することはできませんvolatile。問題は、「読み取り/テスト/待機」または「書き込み/通知」のシーケンスをアトミックに実行できないことです。つまり、競合状態の可能性はありません。

wait/notifyさらに、プリミティブ オブジェクト ミューテックスまたはオブジェクトを使用せずに同等のことを行うことはできませんLock

于 2013-08-18T02:40:11.243 に答える