1. 程式人生 > 其它 >多執行緒通訊:生產者與消費者問題

多執行緒通訊:生產者與消費者問題

技術標籤:Java執行緒java多執行緒

1、wait()、notify/notifyAll() 方法是Object的本地final方法,無法被重寫。
2、wait()使當前執行緒阻塞,前提是 必須先獲得鎖,一般配合synchronized 關鍵字使用,即,一般在synchronized 同步程式碼塊裡使用 wait()、notify/notifyAll() 方法。
3、 由於 wait()、notify/notifyAll() 在synchronized 程式碼塊執行,說明當前執行緒一定是獲取了鎖的。
當執行緒執行wait()方法時候,會釋放當前的鎖,然後讓出CPU,進入等待狀態。
只有當 notify/notifyAll() 被執行時候,才會喚醒一個或多個正處於等待狀態的執行緒,然後繼續往下執行,直到執行完synchronized 程式碼塊的程式碼或是中途遇到wait() ,再次釋放鎖。

也就是說,notify/notifyAll() 的執行只是喚醒沉睡的執行緒,而不會立即釋放鎖,鎖的釋放要看程式碼塊的具體執行情況。所以在程式設計中,儘量在使用了notify/notifyAll() 後立即退出臨界區,以喚醒其他執行緒讓其獲得鎖
4、wait() 需要被try catch包圍,以便發生異常中斷也可以使wait等待的執行緒喚醒。
5、notify 和 notifyAll的區別
notify方法只喚醒一個等待(物件的)執行緒並使該執行緒開始執行。所以如果有多個執行緒等待一個物件,這個方法只會喚醒其中一個執行緒,選擇哪個執行緒取決於作業系統對多執行緒管理的實現。notifyAll 會喚醒所有等待(物件的)執行緒,儘管哪一個執行緒將會第一個處理取決於作業系統的實現。如果當前情況下有多個執行緒需要被喚醒,推薦使用notifyAll 方法。比如在生產者-消費者裡面的使用,每次都需要喚醒所有的消費者或是生產者,以判斷程式是否可以繼續往下執行。

package 生產者與消費者;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
// 先讓廚師生產完,然後喚醒消費者,阻塞廚師,消費者生產完喚醒廚師阻塞自己
public class Demo4 {

    /**
     * 多執行緒通訊問題, 生產者與消費者問題
     *
     * @param args
     */
    public static void main(String[] args) {
        Food f = new Food
(); new Cook(f).start(); new Waiter(f).start(); } //廚師 static class Cook extends Thread { private Food f; public Cook(Food f) { this.f = f; } @Override public void run() { for (int i = 0; i < 100; i++) { if (i % 2 == 0) { f.setNameAndSaste("老乾媽小米粥", "香辣味"); } else { f.setNameAndSaste("煎餅果子", "甜辣味"); } } } } //服務生 static class Waiter extends Thread { private Food f; public Waiter(Food f) { this.f = f; } @Override public void run() { for (int i = 0; i < 100; i++) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } f.get(); } } } //食物 static class Food { private String name; private String taste; //true 表示可以生產 private boolean flag = true; public synchronized void setNameAndSaste(String name, String taste) { if (flag) { this.name = name; try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } this.taste = taste; flag = false; this.notifyAll(); try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } public synchronized void get() { if (!flag) { System.out.println("服務員端走的菜的名稱是:" + name + ",味道:" + taste); flag = true; this.notifyAll(); try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } }

知識點借鑑自https://www.cnblogs.com/moongeek/p/7631447.html