0

Javaのスレッド間の不整合を防ぐためにキーワードを使用することについてはかなりしっかりと理解していると思いますが、そのsynchronizedキーワードを使用しないとどうなるかを完全には理解していません。

たとえば、2つのスレッドによってアクセス/変更されたフィールドがあるとします。

private String sharedString = "";

class OneThread extends Thread {

  private Boolean mRunning = false;

  public OneThread() {}

  public synchronized setRunning(Boolean b) {
    mRunning = b;
  }

  @Override
  public void run() {
    while (mRunning) {
      // read or write to shared string
      sharedString = "text from thread 1";
      System.out.println("String seen from thread 1: " + sharedString);
      super.run();
    }
  }
}

class AnotherThread extends Thread {

  private Boolean mRunning = false;

  public AnotherThread() {}

  public synchronized setRunning(Boolean b) {
    mRunning = b;
  }

  @Override
  public void run() {
    while (mRunning) {
      // read or write to shared string
      sharedString = "text from thread 2";
      System.out.println("String seen from thread 2: " + sharedString);
      super.run();
    }
  }
}

これらのスレッドは両方ともsharedString、synchronizedキーワードを使用せずにフィールドにアクセスして変更しているため、不整合が予想されます。私が疑問に思っているのは、実際に何が起こっているのかということです。デバッグ中に、このような状況で両方のスレッドを注意深く調べたところ、1つのスレッドが一時停止している間でも、その状態が「スティッキー」になる可能性があることに気付きました。

上記の例のために、両方のスレッドがデバッガーで一時停止されていると仮定します。スレッドの1つをステップスルーし、もう1つを一時停止したままにすると、シングルスレッドアプリケーションのように動作することが期待されます。ただし、フィールドを変更した直後に、フィールドにアクセスする次の行で「間違った」値(変更されたばかりの値と一致しない値)が取得されることがよくあります。

このコードは良くないことは知っていますが、マルチスレッドアプリケーションが適切に実装されていない場合に仮想マシンで実際に何が起こるかについての洞察を誰かが提供してくれることを期待しているので、質問をしています。フィールド修正の試みが失敗したスレッドは、まったく効果がありますか?

マルチスレッドコードの実装が不十分だった後、単に「未定義」の動作の領域にあり、この動作について学習する価値がない場合、私はそれで大丈夫です。デバッガーで観察します。

4

2 に答える 2

4

これは、Javaのスレッド間の同期のもう1つの重要な機能である、データの古さの防止によるものです。Javaメモリモデルの一部として、Javaスレッドは共有データの値をキャッシュする場合があります。共有された可変データが同期ブロックでアクセスされるか、揮発性としてマークされていない限り、スレッドが別のスレッドによって行われた更新を認識できるという保証はありません。詳細については、こちらをご覧ください。

于 2012-09-23T22:30:20.683 に答える
0

共有値を変更できるスレッドが他にない場合、印刷出力が「間違っている」ことは実際にはありません(実際には、スレッドが2つしかなく、1つが確実に一時停止している場合のように)。たまたま、これら2つのスレッド(つまりメイン)を「キックオフ」するコードを提供できますか?

于 2012-09-23T23:20:52.063 に答える