1

Java Concurrency in Practiceという本を読んだところ、安全でないプログラムが表示されました。

public class NoVisibility {
  private static boolean ready;
  private static int number;
  private static class ReaderThread extends Thread {
    public void run() {
      while (!ready)  <=== synchronized ?
        Thread.yield();
      System.out.println(number);
    }
  }
  public static void main(String[] args) {
    new ReaderThread().start();
    number = 42;  <=== synchronized ?
    ready = true;  <=== synchronized ?
  }
}

この本には次のように書かれています。

同期には、別の重要で微妙な側面もあります。それは、メモリの可視性です。別のスレッドがオブジェクトを使用しているときに、あるスレッドがそのオブジェクトの状態を変更できないようにするだけでなく、あるスレッドがオブジェクトの状態を変更したときに、他のスレッドが実際に行われた変更を確認できるようにすることも必要です。ただし、同期がないと、これは発生しない可能性があります。

したがって、同時書き込みがなくても、スレッド間で共有されるデータは、あるスレッドによって書き込まれ、別のスレッドによって読み取られるように、書き込みスレッドによって読み取りスレッドに発行されるように同期する必要があることを理解しています。書き込みスレッドは、読み取りスレッドを開始した後、書き込みスレッドによって書き込まれたデータの読み取りをループする別のスレッドを開始できます。データは共有される場合と共有されない場合があります。データが複数の変数である場合、共有される変数と共有されない変数があり、共有順序が異なる場合があります。スレッド間で共有されるすべてのデータを同期する必要があります。次のプログラムが同期ブロックを使用しなかった場合、リーダー スレッドは、ready true を認識しないか、数値セットを確認した後に true を認識します。同期されていないデータは、スレッドにとって古くなります。古いデータを避けるために、書き込みアクセス中だけでなく、読み取りアクセス中にも同期する必要があります。書き込みアクセスを同期するだけでは、データが古くなるのを防ぐことはできません。

このサンプル プログラムを安全にするには、synchronize ステートメントをどのように使用すればよいのでしょうか。

4

1 に答える 1

3

これにより、変数の読み取りと書き込みが同期されるため、変数が表示されます。同じロック (FixedVisibility クラスで) を使用して、静的変数にアクセスして変更します。

public class FixedVisibility {
    private static boolean ready;
    private static int number;
    private static class ReaderThread extends Thread {
        public void run() {
            while (!getReady())
                Thread.yield();
            System.out.println(getNumber());
        }
    }

    public static synchronized boolean getReady() {
        return FixedVisibility.ready;
    }

    public static synchronized void setReady(boolean ready) {
        FixedVisibility.ready = ready;
    }

    public static synchronized int getNumber() {
        return FixedVisibility.number;
    }    

    public static synchronized void setNumber(int number) {
        FixedVisibility.number = number;
    }

    public static void main(String[] args) {
        new ReaderThread().start();
        FixedVisibility.setNumber(42); 
        FixedVisibility.setReady(true); 
    }
}
于 2015-08-11T15:56:28.133 に答える