web-dev-qa-db-ja.com

id = 1-idはアトミックですか?

OCPの291ページからJava SE 6プログラマー模擬試験、質問25:

_public class Stone implements Runnable {
    static int id = 1;

    public void run() {
        id = 1 - id;
        if (id == 0) 
            pick(); 
        else 
            release();
    }

    private static synchronized void pick() {
        System.out.print("P ");
        System.out.print("Q ");
    }

    private synchronized void release() {
        System.out.print("R ");
        System.out.print("S ");
    }

    public static void main(String[] args) {
        Stone st = new Stone();
        new Thread(st).start();
        new Thread(st).start();
    }
}
_

答えの1つは次のとおりです。

出力は_P Q P Q_になる可能性があります

私はこの答えを正しいとマークしました。私の推論:

  1. 2つのスレッドを開始しています。
  2. 最初にrun()に入ります。
  3. JLS 15.26.1 によると、最初に_1 - id_を評価します。結果は_0_です。スレッドのスタックに保存されます。その_0_を静的idに保存しようとしていますが...
  4. ブーム、スケジューラは実行する2番目のスレッドを選択します。
  5. したがって、2番目のスレッドはrun()に入ります。静的idは_1_のままなので、メソッドpick()を実行します。 _P Q_が出力されます。
  6. スケジューラは実行する最初のスレッドを選択します。スタックから_0_を取得し、静的idに保存します。したがって、最初のスレッドもpick()を実行し、_P Q_を出力します。

しかし、本にはこの答えが間違っていると書かれています:

_id = 1 - id_という行は、_0_と_1_の間でidの値を交換するため、正しくありません。同じメソッドが2回実行される可能性はありません。

同意しません。上記のシナリオには、ある程度のチャンスがあると思います。このようなスワップはアトミックではありません。私が間違っている?

74

私が間違っている?

いいえ、あなたは完全に正しいです-あなたの例のタイムラインもそうです。

アトミックではないことに加えて、同期がなく、フィールドが揮発性でない場合、idへの書き込みが他のスレッドによって取得されるとは限りません。

このような参照資料が正しくないことはやや当惑しています:(

78
Jon Skeet