3

私はJavaの同時実行性について読んでいて、同じロックを使用する2つのスレッドの同期ブロックが変数の可視性にも影響するという事実を忘れていました.それらは「揮発性」として定義されていませんでした. このようなコードがある場合

Object lock = new Object();
boolean a = false, b = false, c = false;

void threadOne() {

   a = true;
   synchronized(lock) {
      b = true;
   }
   c = true;

}

void threadTwo() {

   while (true) {
      synchronized(lock) {
         if (a && b && c) break;
      }
   } 

}

... そして、threadOne と threadTwo は異なるスレッドによって呼び出されます。

  1. コードが while ループから抜けることが保証されていますか?

  2. 式から変数 c を削除するとどうなるでしょうか。同期ブロック内にあったため、b のみが threadTwo に表示されることが保証されているかどうか疑問に思っています。

4

2 に答える 2

3

コードが while ループから抜けることが保証されていますか?

いいえ。Java メモリ モデルは、「発生前」の関係で定義されています。

2 つのアクションは、先行発生関係によって順序付けできます。あるアクションが別のアクションの前に発生する場合、最初のアクションは 2 番目のアクションよりも前に表示され、順序付けされます。

仕様は次のように続けています。

アクション x が後続のアクション y と同期する場合、hb(x, y) も得られます。

wherehbは、事前発生を表し、

モニター m のロック解除アクションは、m の後続のすべてのロック アクションと同期します (「後続」は同期順序に従って定義されます)。

また、次の点にも注意してください。

hb(x, y) と hb(y, z) の場合、hb(x, z) です。

したがって、あなたの例では、synchronized(lock)aroundbは次の読み取りの事前発生関係を確立するため、 の値はb、 も使用する他のスレッドで表示されることが保証されますsynchronized(lock)。明示的に、

hb(write to b in threadOne, unlock in threadOne) AND 
hb(unlock in threadOne, lock in threadTwo) AND 
hb(lock in threadTwo, read from a in threadTwo) IMPLIES 
hb(write to b in threadOne, read from b in threadTwo) 

同様にa、他のスレッドから見えることが保証されます。明示的に、

hb(write to a in threadOne, lock in threadOne) AND 
hb(lock in threadOne, unlock in threadOne) AND 
hb(unlock in threadOne, lock in threadTwo) AND 
hb(lock in threadTwo, read a in threadTwo) IMPLIES 
hb(write to a in threadOne, read a in threadTwo). 

の書き込みとそれに続く読み取りにcは、事前発生の関係がないため、仕様によると、 への書き込みcが必ずしも に表示されるとは限りませんthreadTwo

式から変数 c を削除するとどうなるでしょうか。同期ブロック内にあったため、b のみが threadTwo で表示されることが保証されているかどうか疑問に思っています。

はい、上記を参照してください。

于 2013-01-15T00:18:48.273 に答える
0

各スレッドが、質問で定義した(不完全な)クラスの同じインスタンスを共有していると仮定すると、次のようになります。

コードがwhileループから抜け出すことが保証されていますか?

実際には、そうです。threadOneメソッドでbを設定するために、ロックは短時間だけ保持されます。threadTwoには、threadOneが同期ブロックを実行できるようにするのに十分なコンテキストスイッチがあります。「実際」の意味:非常にありそうもないシナリオ(およびJVMスレッドの実装が不十分)では、threadTwoがifチェックのために同期ロックを再取得し続けている間、threadOneが同期ブロックから外れる可能性があります。(実際、OPシナリオが完了しない実用的な例を作成するように誰にでも挑戦します)。

方程式から変数cを削除するとどうなりますか?同期ブロック内にあったため、threadTwoでbのみが表示されることが保証されているのではないかと思います。

同じ。実際には、そうです。

追加のクレジット(チャレンジ)については、次のコードを実行するJVMを見つけて、終了しないようにします。

public class SyncTest {

  public static void main(String args[]) throws Exception {

          final Shared s = new Shared();
          Thread t1 = new Thread () { public void run() { s.threadOne(); } };
          Thread t2 = new Thread () { public void run() { s.threadTwo(); } };

          t2.start();
          t1.start();
  }
}

class Shared {

  Object lock = new Object();
  boolean a = false, b = false, c = false;

  void threadOne() {
    a = true;
    synchronized(lock) {
       b = true;
    }
    c = true;
  }

  void threadTwo() {
    while (true) {
      synchronized(lock) {
         if (a && b && c) break;
      }
    }
  }
}
于 2013-01-15T00:15:19.117 に答える