2

このページの著者は、以下の 2 番目のコード例には同期の問題があるが、コードは 100 回で約 99 回動作すると述べています。そのページの 2 つのプログラムの動作上の違いはわかりません。


前の 2 つを組み合わせるやや一般的な解決策は、フィールドの値をローカル変数にコピーしてから、ローカル変数のみを変更することです。フィールドはメソッド内で変更されません。例えば、

public class Counter {

  int count = 0;

  public void count() {
    int count = this.count;
    int limit = count + 100;
    while (count++ != limit) System.out.println(count); 
  }

}

ローカル変数 count がフィールド カウントをどのようにシャドウするか、および this キーワードを使用してシャドウの外側のフィールド カウントを参照する方法に注意してください。

このトリックは、メソッドが完了したときに、変更された変数をフィールドに戻す必要がない場合に主に役立ちます。以下は状態を保存しますが、まだ明らかでない同期の問題の影響を受けます。

public class Counter {

  private int count = 0;

  public void count() {
    int count = this.count;
    int limit = count + 100;
    while (count++ != limit) System.out.println(count);
    this.count = count; 
  }

}

実際、これは 100 回のうち 99 回は機能するため、元の例よりもさらに悪い可能性があります。ソース コードで見つけないと、このバグを特定するのは非常に困難です。

4

1 に答える 1

2

this.count問題は、への変更がアトミックではないという事実にあります。

2 つのスレッドがこの関数を呼び出しており、this.count現在 に設定されているとし0ます。

0スレッド 1 はそのローカルにロードされ、countそれを にインクリメントし始めます101(これ100まで考えられていcountたのは、制限に達した後に でもう一度インクリメントするためですcount++ != limit)。

その間、スレッド 2 が入ってきて、まだに設定されてthis.countいるため、それを取得して にインクリメントし始めます。0101

ある時点で、両方とも行に到達しthis.count = count(順序は関係ありません)、両方ともthis.count101 に設定されます。

最後に設定する必要があったのは(が思うに、確かにどこかのマーク202の周りにあるはずです)。200

コードの最初のビットが有効である理由は、実際にはthis.count値を変更しようとしていないため、競合状態が発生する可能性がないためです。

于 2013-02-12T00:30:21.023 に答える