Java 多執行緒(Java.Thread)------ 執行緒協作(生產者消費者模式)

沒有陽光,也一樣燦爛發表於2020-12-13

執行緒協作

  • 應用場景:生產者消費者模式

    • 假設倉庫中只能存放一件產品,生產者將生產出來的產品放入倉庫,消費者將倉庫中產品取走消費
    • 如果倉庫中沒有產品,則生產者將產品放入倉庫,否則停止生產並等待,直到倉庫中的產品被消費者取走為止
    • 如果倉庫中放有產品,則消費者可以將產品直接取走,否則停止消費並等待,直到倉庫中再次放入產品為止
  • 分析:這是一個執行緒同步問題,生產者和消費者共享同一個資源,並且生產者和消費者相互依賴,互為條件

  • 在生產者和消費者問題中,僅有synchronized是不夠的

    • synchronized可阻止併發更新同一個共享資源,實現了同步
    • synchronized不能用來實現不同執行緒之間的訊息傳遞
  • 解決執行緒之間通訊問題的幾個方法:

    • wait():表示執行緒一直等待,直到其他執行緒通知,與sleep()不同,會釋放鎖
    • wait(long timeout):指定等待的毫秒數
    • notify():喚醒一個處於等待狀態的執行緒
    • notifyAll():喚醒同一個物件上所有呼叫wait()方法的執行緒,優先順序高的執行緒優先排程
    • 以上方法都是Object類的方法,都只能在同步方法或者同步程式碼塊中使用,否則會丟擲異常IlledalMonitorStateException
  • 解決方式一:併發協作模式“生產者/消費者模式”---->管程法

    • 生產者:負責生產資料的模組(可能是方法,物件,執行緒,程式)
    • 消費者:負責處理資料的模組(可能是方法,物件,執行緒,程式)
    • 緩衝區:消費者不能直接使用生產者的資料,他們之間有個緩衝區
    • 生產者將生產好的資料放到緩衝區,消費者從緩衝區拿出資料
package www.bh.c.threadtest;
//併發協作模式“生產者/消費者模式”---->管程法
public class PCTest {
    public static void main(String[] args) {
        Buffer buffer = new Buffer();
        new Producer(buffer).start();
        new Consumer(buffer).start();
    }
}
//生產者
class Producer extends Thread{
    Buffer buffer;
    public Producer(Buffer buffer){
        this.buffer=buffer;
    }
//生產
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            buffer.push(new Product(i));
            System.out.println("生產了"+i+"個產品");
        }
    }
}
//消費者
class Consumer extends Thread{
    Buffer buffer;
    public Consumer(Buffer buffer){
        this.buffer=buffer;
    }
//消費
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("消費了---->"+buffer.pull().id+"個產品");
        }
    }
}

//產品
class Product{
    int id;
    public Product(int id) {
        this.id = id;
    }
}
//緩衝區
class Buffer{
    //緩衝區大小
    Product[] products=new Product[10];
    //緩衝區計數器
    int count=0;
    //生產者放入產品
    public synchronized void push(Product product){
             //如果緩衝區已滿,通知消費者消費
        if (count==products.length){
           //等待消費,生產暫停
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }else {
            //如果沒有滿,就繼續放入產品
            products[count]=product;
            count++;
            //通知消費
            this.notifyAll();
        }
    }
    //消費者消費產品
    public synchronized Product pull(){
        //判斷是否有產品可以消費
        if(count==0){
           //消費者等待生產
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        count--;
        Product product=products[count];
        //消費完了,通知生產者生產
        this.notifyAll();
        return product;
    }
}

相關文章