[英]When and How to use wait() and notify()
我從SO找到了這個例子。 現在,我試圖了解wait()
和notify()/notifyAll()
的用法。 在哪種情況下以及為什么需要這樣做。
class BlockingQueue<T> {
private Queue<T> queue = new LinkedList<T>();
private int capacity;
public BlockingQueue(int capacity) {
this.capacity = capacity;
}
public synchronized void put(T element) throws InterruptedException {
while (queue.size() == capacity) {
System.out.println("Waiting...");
wait();
}
queue.add(element);
notify(); // notifyAll() for multiple producer/consumer threads
}
public synchronized T take() throws InterruptedException {
while (queue.isEmpty()) {
wait();
}
T item = queue.remove();
notify(); // notifyAll() for multiple producer/consumer threads
return item;
}
}
因此,實現了Runnable
和重寫的run()
方法,如下所示
@Override
public void run() {
// synchronized (this) {
BlockingQueue<Integer> s = new BlockingQueue(10);
for (int i = 0; i < 12; i++) {
try {
s.put(i);
if (i > 9) {
System.out.println(Thread.currentThread().getName() + " : " + s.take());
}
System.out.println(Thread.currentThread().getName() + " ExtendsThread : Counter : " + i);
} //}
//notify();
catch (InterruptedException ex) {
Logger.getLogger(ExtendsThread.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
並且,如下運行線程
ImplementsRunnable rc = new ImplementsRunnable();
Thread t1 = new Thread(rc, "A");
t1.start();
當我運行它時,它在counter : 9
之后卡住,並一直等待着永遠。 有人建議我這是怎么了?
您的概念有些瑕疵。 BlockingQueue
可以充當生產者/消費者模式中的橋梁。
也就是說,它允許一個線程向其中寫入內容,而另一個線程從中讀取內容,但是這樣做的前提是:
在這種情況下, wait
和notify
是BlockingQueue
實例的內部消息傳遞
您可以查看“ 固有鎖定和同步” 。
因此,您應該使用(至少)兩個,而不是僅使用一個線程,一個農產品和一個消費者...
這需要一個BlockingQueue
實例,並向其中添加int
值。 每次停止1秒鍾,然后添加下一個
public class Producer implements Runnable {
private BlockingQueue<Integer> queue;
public Producer(BlockingQueue<Integer> queue) {
this.queue = queue;
}
@Override
public void run() {
for (int index = 0; index < 10; index++) {
try {
System.out.println("Put " + index);
queue.put(index);
Thread.sleep(1000);
} catch (InterruptedException ex) {
}
}
}
}
使用者使用BlockQueue
並從中讀取int
值,該值將被阻塞直到值存在。
public class Consumer implements Runnable {
private BlockingQueue<Integer> queue;
public Consumer(BlockingQueue<Integer> queue) {
this.queue = queue;
}
@Override
public void run() {
try {
while (true) {
Integer value = queue.take();
System.out.println("Took " + value);
}
} catch (InterruptedException ex) {
Logger.getLogger(JavaApplication220.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
您可以使用類似...
BlockingQueue bq = new BlockingQueue(10);
Thread p = new Thread(new Producer(bq));
Thread c = new Thread(new Consumer(bq));
c.setDaemon(true);
c.start();
p.start();
您應該注意, put
消息之間的延遲很小,但是took
消息之間幾乎沒有延遲。 這是正在執行的隊列。 Consumer
正在阻止/等待隊列中的東西給它。
您可以與“ Producer
和“ Consumer
一起玩耍,也許可以改變他們的時間(例如,在拿一件物品之前,“ Consumer
會有更長的延遲),以了解這可能會帶來怎樣的不同影響
當我運行它時,它在計數器9之后停滯不前,並一直等待着永遠
這可能是因為您已經超出了隊列的容量,並且put
方法一直處於阻塞狀態,直到您從隊列中取出某些東西為止(您實際上有一個死鎖,隊列正在等待您從中取出某些東西,但是您可以計算負擔,因為你鎖定在put
)
要記住的事情:
BlockingQueue
的相同實例 notify
將喚醒一個在監視器鎖的wait
方法的同一實例上等待的對象。 沒有辦法知道哪一個。 如果您有多個使用者,但不關心數據的處理順序,例如,這可能很有用。 更新了其他示例
因此,這將Thread.sleep
從Producer
Thread.sleep
(並允許生產者產生100個值),並將Thread.sleep
添加到Consumer
。
這樣, Producer
將在Consumer
耗盡其容量之前達到其容量,迫使其等待直到Consumer
可以從中獲取價值為止。
public class Producer implements Runnable {
private BlockingQueue<Integer> queue;
public Producer(BlockingQueue<Integer> queue) {
this.queue = queue;
}
@Override
public void run() {
for (int index = 0; index < 100; index++) {
try {
System.out.println("Put " + index);
queue.put(index);
} catch (InterruptedException ex) {
}
}
}
}
public class Consumer implements Runnable {
private BlockingQueue<Integer> queue;
public Consumer(BlockingQueue<Integer> queue) {
this.queue = queue;
}
@Override
public void run() {
try {
while (true) {
Integer value = queue.take();
System.out.println("Took " + value);
Thread.sleep(1000);
}
} catch (InterruptedException ex) {
}
}
}
在此處添加printlns
public synchronized void put(T element) throws InterruptedException {
while (queue.size() == capacity) {
System.out.println("blocked");
wait();
}
queue.add(element);
notify(); // notifyAll() for multiple producer/consumer threads
System.out.println("put "+ element);
}
public synchronized T take() throws InterruptedException {
while (queue.isEmpty()) {
wait();
}
T item = queue.remove();
notify(); // notifyAll() for multiple producer/consumer threads
System.out.println("removed " + item);
return item;
}
並運行此測試
public static void main(String argv[]) throws Exception {
final BlockingQueue q = new BlockingQueue(2);
new Thread() {
public void run() {
try {
Thread.sleep(5000);
q.take();
} catch (Exception e) {
e.printStackTrace();
}
};
}.start();
q.put(1);
q.put(2); // will block here until tread 2 takes an element and reduces the capacity
q.put(3);
}
它將打印
put 1
put 2
blocked
removed 1
put 3
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.