利用wait()和notify()實現生產者與消費者問題
生產者與消費者問題是併發程式設計裡面的經典問題,下面用wait()和notify()來實現消費者執行緒和生產者執行緒的併發執行。
說之前先講幾個概念:
wait()與sleep()的區別:
1.首先sleep()是Thread()類的方法,而wait()是Object類的方法,包括notify(),notifyAll()都是Object類的方法
2.sleep()方法是休眠,阻塞執行緒的同時仍然會持有鎖,也就是說它休眠期間其他執行緒仍然無法獲得鎖,同時sleep()休眠時自動醒 的;而呼叫wait()方法時,則自動釋放鎖,也就是其他執行緒可以獲得鎖,而且wait()是無法自動醒的,只有通過notify()或
notify()與notifyAll()的區別
notify()一次只能啟用一個對這個物件進行wait()的執行緒,當多個執行緒都對此物件wait()時,是隨機挑一個notify(),而notifyAll()是一次 性啟用所以對此物件進行wait()的執行緒。
接下來說說利用wait()和notify()來實現生產者和消費者併發問題:
顯然要保證生產者和消費者併發執行不出亂,主要要解決:當生產者執行緒的快取區為滿的時候,就應該呼叫wait()來停止生產者繼續生產,而當生產者滿的緩衝區被消費者消費掉一塊時,則應該呼叫notify()喚醒生產者,通知他可以繼續生產;同樣,對於消費者,當消費者執行緒的快取區為空的時候,就應該呼叫wait()停掉消費者執行緒繼續消費,而當生產者又生產了一個時就應該呼叫notify()來喚醒消費者執行緒通知他可以繼續消費了。
當然我們必須在wait()和notify()的時候鎖住我們所要操作的物件,這裡即快取區,下面是一個使用wait()的notify()的規範程式碼模板:
synchronized (sharedObject) { //鎖住操作物件
while (condition) { //當某個條件下
sharedObject.wait(); //進入wait
}
// 做了什麼事,就可以啟用
shareObject.notify();
}
下面就貼一下wait和notify實現一個生產者執行緒和一個消費者執行緒併發執行的程式碼:
import java.util.LinkedList; import java.util.Queue; import java.util.Random; public class ProducerConsumerInJava { public static void main(String args[]) { System.out.println("How to use wait and notify method in Java"); System.out.println("Solving Producer Consumper Problem"); Queue<Integer> buffer = new LinkedList<>(); int maxSize = 10; Thread producer = new Producer(buffer, maxSize, "PRODUCER"); Thread consumer = new Consumer(buffer, maxSize, "CONSUMER");<span style="font-family: Arial, Helvetica, sans-serif;"> </span>
<span style="font-family: Arial, Helvetica, sans-serif;"> //開啟生產者和消費者執行緒</span>
producer.start();
consumer.start(); }
}
//生產者執行緒
class Producer extends Thread
{ private Queue<Integer> queue;
private int maxSize;
public Producer(Queue<Integer> queue, int maxSize, String name){
super(name); this.queue = queue; this.maxSize = maxSize;
}
@Override public void run()
{
while (true)
{
synchronized (queue) {
while (queue.size() == maxSize) { //當快取區滿的時候
try {
//進入wait
queue.wait();
} catch (Exception ex) {
ex.printStackTrace();
}
}
//快取區不為空的時候就可以繼續生產,生產後喚醒消費者執行緒的wait
queue.add(i);
queue.notifyAll();
}
}
}
}
//消費者執行緒
class Consumer extends Thread {
private Queue<Integer> queue;
private int maxSize;
public Consumer(Queue<Integer> queue, int maxSize, String name){
super(name);
this.queue = queue;
this.maxSize = maxSize;
}
@Override public void run() {
while (true) {
synchronized (queue) {
while (queue.isEmpty()) { //當快取區為空的時候
try {
queue.wait(); //進入wait
} catch (Exception ex) {
ex.printStackTrace();
}
}
//當快取區不為空的時候,就可以喚醒所有的wait的消費者執行緒或者生產者執行緒
queue.notifyAll();
}
}
}
}
所以從以上可以看出,notify()實際上是可以實現執行緒間通訊,可以在一個執行緒裡通知喚醒另一個執行緒裡的wait,實質上也是因為他們 wait和notify操作的是同一物件,這也是因為wait和notify是相對於Object的。
這就是利用wait和notify實現生產者和消費者問題。