1. 程式人生 > 其它 >多執行緒---多生產者與多消費者 (if/while之間的區別)

多執行緒---多生產者與多消費者 (if/while之間的區別)

技術標籤:JavaJava高階程式設計多執行緒java

引入

在這裡插入圖片描述
這是一個執行緒同步問題,生產者和消費者共享一個資源,並且生產者相互依賴,互為條件。

  • 對於生產者,沒有生產產品之前,要通知消費者等待,生產了產品後,要通知消費者可以消費
  • 對於消費者,在消費之後,要通知生產者自己結束了消費,可以生產產品了
  • synchronized 關鍵字可以阻止併發地更新同一個資源,可以實現同步,但是不能用來實現不同執行緒間的訊息傳遞,也即是通訊
wait讓執行緒一直等待,直到其它執行緒通知,會釋放鎖,可以傳遞一個型別為long的引數,表示指定等待的毫秒數
notify喚醒一個處於等待狀態的執行緒
notifyAll喚醒同一個物件上所有呼叫wait方法的執行緒,優先順序高的優先排程

上述方法均屬於Object類的方法,只能在同步方法或者同步程式碼中使用,否則會丟擲InterruptedException異常

併發協作模型“生產者/消費者模式” 管程法

  • 生產者:負責生產資料的模組
  • 消費者:負責處理資料的模組
  • 緩衝區:消費者不能直接使用生產者的資料,要通過緩衝區將生產者的資料放入到緩衝區中,消費者再從緩衝區裡面拿出資料

緩衝區

class Container<T>{
    private LinkedList<T> list = new LinkedList<T>();
    private
final int MAX = 100; private int count = 0; //往緩衝區裡面新增商品 public synchronized void put(T t){ while(list.size() == MAX){ try{ this.wait();; }catch(InterruptedException e){ e.printStackTrace(); } } list.
add(t); System.out.println(Thread.currentThread().getName() + t); this.notifyAll(); } //從緩衝區裡面消費商品 public synchronized void get() { while (list.size() == 0){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } String t = (String) list.removeFirst(); System.out.println(Thread.currentThread().getName() + t); this.notifyAll(); } }

消費者

class Customer implements Runnable{
    Container container;

    public Customer(Container container) {
        this.container = container;
    }

    @Override
    public void run() {
        while (true){
            container.get();
        }
    }
}

生產者

class Productor implements Runnable{
    Container container;
    String name;
    
    public Productor(Container container,String name) {
        this.container = container;
        this.name = name;
    }

    @Override
    public void run() {
        while (true){
            container.put(name);
        }
    }
}

主函式

public class testThread{
    public static void main(String[] args) {
    
        Container<String> container = new Container();
        
        new Thread(new Productor(container,"桃子"),"生產者1").start();
        new Thread(new Customer(container),"消費者1").start();
        new Thread(new Customer(container),"消費者2").start();
        new Thread(new Productor(container,"雪梨"),"生產者2").start();

    }
}

注意

在多生產者的情況下我們判斷的時候要用 while 來做判斷而不是if

我們假設執行緒的排程是這樣的,我們假設緩衝區最大容量為7,此時是已經達到最大容量,生產者執行緒都會被阻塞(此時生產者執行緒A已經經過 if 判斷,在wait處等待,生產者執行緒B也通過了 if判斷,在wait處等待),當消費者通知生產者執行緒可以生產時(我們呼叫的是notifyAll方法),所有被阻塞的生產者執行緒都會被喚醒(A和B都會被喚醒),假如是生產者執行緒A獲得了執行的機會,即獲得了鎖,而生產者執行緒B 繼續在鎖池中等待,此時生產者執行緒B是醒著的。假設生產者又把緩衝區生產滿了,並且釋放鎖,生產者執行緒B獲得鎖,在這種情況下,B已經通過了if判斷,即使緩衝區已經滿了,但是B一樣可以往裡面新增資料,就會造成錯誤。假如我們用的是while