いいえ、同期は、どちらThread
が最初に到達するかについて保証しません。Thread
一度に複数の同期ブロックにアクセスできないことを保証するだけです。
synchronized
ブロックは、ドアに鍵がかかっている部屋と考えてください。誰が最初にドアにたどり着くかはわかりませんが、ドアに入るとドアに鍵をかけます。
他の人は、部屋にいる人が部屋を出る準備ができてドアのロックを解除するまで待たなければなりません。それが起こると、誰もが再びドアに入るために競争します.
それはすべて、s をオフにする順序によって異なりますThread
。ただし、JVM が と をランダムにサスペンドする可能性があるため、保証はありませThread
ん。例えるなら、先頭に立ってドアにたどり着く人がバナナの皮につまずくかもしれません。可能性は低いですが、常に可能です。Thread
yield
保証が必要な場合は、wait
/ notify
- を実行する必要があります。これにより、読み取りスレッドが をチェックしflag
、 である場合false
はループ内で一時停止します。
次に、書き込みスレッドは を設定しflag
、読み取りスレッドを起動するロック モニターに通知します。
Lock
Java 5 のand APIを使用した例を次に示します。and /よりもそれを使用する必要がCondition
あると言っているわけではありません。synchronized
wait
notify
はReader
を取得し、ループでフラグをlock
チェックします。ready
フラグがオンの場合はfalse
オンawait
です。これにより、 がアトミックに解放され、 がlock
中断されThread
ます。
一方、Writer
は を取得し、およびフラグlock
を設定します。次に、 を呼び出して解放します。data
ready
signalAll
lock
これによりが起動し、 as がReader
読み取られ、ステートメントに進みます。ready
true
print
出力は常に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);
}
}