3

SO やその他の場所には、事前発生の関係について多くの投稿がありますが、私の質問に対する決定的な答えを見つけるのに驚くほど苦労しています。

次の 2 つの Java スレッドについて考えてみましょう。

最初に、flag == falseそしてdata == 0

T1

data = 42;
synchronized(m) {
  flag = true;
}

T2

boolean f;
synchronized(m) {
  f = flag;
}
if (f) {
  int x = data;
}

上記のコードによると、値またはfのいずれかが割り当てられる可能性があると思いますが、保証はありません。これは正しいです?truefalse

ここで、2 つのsynchronizedステートメントが に変更された場合、命令は常に命令の前に発生するため、常に値が割り当てられるsynchronized(flag)と思います。これは正しいです?flag = truef = flagftrue

4

1 に答える 1

6

いいえ、同期は、どちらThreadが最初に到達するかについて保証しません。Thread一度に複数の同期ブロックにアクセスできないことを保証するだけです。

synchronizedブロックは、ドアに鍵がかかっている部屋と考えてください。誰が最初にドアにたどり着くかはわかりませんが、ドアに入るとドアに鍵をかけます。

他の人は、部屋にいる人が部屋を出る準備ができてドアのロックを解除するまで待たなければなりません。それが起こると、誰もが再びドアに入るために競争します.

それはすべて、s をオフにする順序によって異なりますThread。ただし、JVM が と をランダムにサスペンドする可能性があるため、保証はありませThreadん。例えるなら、先頭に立ってドアにたどり着く人がバナナの皮につまずくかもしれません。可能性は低いですが、常に可能です。Threadyield

保証が必要な場合は、wait/ notify- を実行する必要があります。これにより、読み取りスレッドが をチェックしflag、 である場合falseはループ内で一時停止します。

次に、書き込みスレッドは を設定しflag、読み取りスレッドを起動するロック モニターに通知します。

LockJava 5 のand APIを使用した例を次に示します。and /よりもそれを使用する必要Conditionあると言っているわけではありません。synchronizedwaitnotify

Readerを取得し、ループでフラグをlockチェックします。readyフラグがオンの場合はfalseオンawaitです。これにより、 がアトミックに解放され、 がlock中断されThreadます。

一方、Writerは を取得し、およびフラグlockを設定します。次に、 を呼び出して解放します。datareadysignalAlllock

これによりが起動し、 as がReader読み取られ、ステートメントに進みます。readytrueprint

出力は常に42(never -1) になります。

public class App {

    static volatile boolean ready = false;
    static volatile int data = -1;

    private static class Reader implements Runnable {

        private final Lock lock;
        private final Condition condition;

        public Reader(Lock lock, Condition condition) {
            this.lock = lock;
            this.condition = condition;
        }

        @Override
        public void run() {
            lock.lock();
            try {
                while (!ready) {
                    try {
                        condition.await();
                    } catch (InterruptedException ex) {
                        //oh well
                    }
                }
                System.out.println(data);
            } finally {
                lock.unlock();
            }
        }
    }

    private static class Writer implements Runnable {

        private final Lock lock;
        private final Condition condition;

        public Writer(Lock lock, Condition condition) {
            this.lock = lock;
            this.condition = condition;
        }

        @Override
        public void run() {
            lock.lock();
            try {
                data = 42;
                ready = true;
                condition.signalAll();
            } finally {
                lock.unlock();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        final ExecutorService executorService = Executors.newFixedThreadPool(2);
        final Lock lock = new ReentrantLock();
        final Condition condition = lock.newCondition();
        executorService.execute(new Reader(lock, condition));
        executorService.execute(new Writer(lock, condition));
        executorService.shutdown();
        executorService.awaitTermination(1, TimeUnit.DAYS);
    }
}
于 2013-04-26T15:01:28.247 に答える