プロデューサ/コンシューマをモデル化したこのシンプルな並行性のOracleの問題で数日間苦労しました。これは私がguardedブロック、wait、およびnotifyAllを使用した初めてのことです。しかし、私はこれらの方法が何をするか知っています。私はどのようなステップが最初に起こるかは分かりません。私は下に行くことができるように問題を追跡するつもりで、あなたが私が正しいかどうか教えてくれます。Javaで保護されたブロックをトレースする
- プロデューサ/コンシューマスレッドは、メインスレッドから開始されます。それぞれに同じDropインスタンスが与えられます。
- コンシューマスレッドがプロデューサより速い場合、プロデューサは組み込みのロックを取得し、メッセージをループ内で
drop.take()
から出力しようとします。しかし、プロデューサーはempty
が真であるため、消費者にメッセージを与えていません。この結果、スレッドが中断され、ロックが解除されます。それは今待っている。 - プロデューサスレッドは、ループ内で
drop.put()
を呼び出します。empty
がtrueであり、Consumerのメッセージを準備する必要があるため、ドロップ時の固有のロックを取得してメソッドを続行します。empty
をfalseに設定してメッセージを格納します。 Consumer Threadを起動するnotifyAll()
が呼び出されます。empty
がfalseになり、ロックが解除されるため、プロデューサも待機しています。 drop.take()
が通知され、プロデューサが本質的なロックオンのロックを持っていたため、このメソッドを起動します。Empty
がtrueに設定され、メッセージが返され、ループ内に印刷されます。新しいメッセージが必要なため、プロデューサースレッドに目を覚ますように通知するようになりました。- プロデューサーが待っていました。
empty
がtrueで、スレッドに通知され(ロックがアクセスされたため)、スレッドは目覚めて別のメッセージを生成することができます。
ドロップクラス
package Store;
public class Drop {
// Message sent from producer
// to consumer.
private String message;
// True if consumer should wait
// for producer to send message,
// false if producer should wait for
// consumer to retrieve message.
private boolean empty = true;
public synchronized String take() {
// Wait until message is
// available.
while (empty) {
try {
wait();
} catch (InterruptedException e) {}
}
// Toggle status.
empty = true;
// Notify producer that
// status has changed.
notifyAll();
return message;
}
public synchronized void put(String message) {
// Wait until message has
// been retrieved.
while (!empty) {
try {
wait();
} catch (InterruptedException e) {}
}
// Toggle status.
empty = false;
// Store message.
this.message = message;
// Notify consumer that status
// has changed.
notifyAll();
}
}
消費者クラス:
package Store;
import java.util.Random;
public class Consumer implements Runnable {
private Drop drop;
public Consumer(Drop drop) {
this.drop = drop;
}
public void run() {
Random random = new Random();
for (String message = drop.take();
! message.equals("DONE");
message = drop.take()) {
System.out.format("MESSAGE RECEIVED: %s%n", message);
try {
Thread.sleep(random.nextInt(5000));
} catch (InterruptedException e) {}
}
}
}
プロデューサークラス:
package Store;
import java.util.Random;
public class Producer implements Runnable {
private Drop drop;
public Producer(Drop drop) {
this.drop = drop;
}
public void run() {
String importantInfo[] = {
"Mares eat oats",
"Does eat oats",
"Little lambs eat ivy",
"A kid will eat ivy too"
};
Random random = new Random();
for (int i = 0;
i < importantInfo.length;
i++) {
drop.put(importantInfo[i]);
try {
Thread.sleep(random.nextInt(5000));
} catch (InterruptedException e) {}
}
drop.put("DONE");
}
}
メインスレッド:
public class ProducerConsumerExample {
public static void main(String[] args) {
Drop drop = new Drop();
(new Thread(new Producer(drop))).start();
(new Thread(new Consumer(drop))).start();
}
}
他のメッセージで繰り返される最初のメッセージの手順をたどってきました。私はあなたが待っている方法についての言葉が好きで、ロックを解除しました。 – retchers