程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 再談線程:生產者與消費者

再談線程:生產者與消費者

編輯:關於JAVA

場景描述:

一個倉庫,生產者在工廠裡生產了產品後,將產品存放到倉庫裡,倉庫存放數量有限,當滿倉後,停 止生產,直到有消費著將產品消費後才繼續生產;消費者從倉庫裡提取產品,當倉庫空倉時,停止消費產 品,直到倉庫中有產品時,才繼續消費產品。

代碼的實現(調整線程sleep時間可以實現生產速度與消費速度的不同):

TestProduceAndConsumer.java

package com.nantian;

import java.util.Random;

public class TestProduceAndConsumer {
    public static void main(String[] args) {
        // 創建一個工廠對象
        ProductFactory pf = new ProductFactory();
        // 創建一個生產者和一個消費者,傳遞工廠的引用,保證兩者操作的是同一個工廠
        Producer p = new Producer(pf);
        Consumer c = new Consumer(pf);
        // 啟動兩個線程
        p.start();
        c.start();
    }
}

// 產品工廠
class ProductFactory {
    // product表示倉庫
    private char[] product = { ' ', ' ', ' ', ' ', ' '};
    // flag標記產品數量
    private int flag = 0;

    // 生產產品
    public synchronized void produceProduct(char p) throws InterruptedException {
        // 判斷產品是否滿倉,以便決定是否繼續生產
        if (flag == product.length) {
            this.wait();
        }
        // 當代碼執行到這裡,一定不是滿倉狀態
        product[flag++] = p;
        // 查看此時倉庫狀態(這裡不屬於業務邏輯部分)
        System.out.print(p + "被生產,當前倉庫狀態:");
        for (char tmp : product) {
            System.out.print(tmp);
        }
        System.out.println();
        // 生產方法完成,如果存在等待隊列中的線程,應該喚醒
        this.notifyAll();
    }

    // 消費產品
    public synchronized char consumeProduct() throws InterruptedException {
        // 判斷倉庫是否空倉,以便決定是否消費產品
        if(flag == 0) {
            this.wait();
        }
        // 當代碼執行到這裡,一定不是空倉狀態
        char p = product[--flag]; product[flag]=' ';
        // 查看此時倉庫狀態(這裡不屬於業務邏輯部分)
        System.out.print(p + "被消費,當前倉庫狀態:");
        for(char tmp : product) {
            System.out.print(tmp);
        }
        System.out.println();
        // 消費方法完成,如果存在等待隊列中的線程,應該喚醒
        this.notifyAll();
        return p;
    }
}

// 生產者
class Producer extends Thread {
    private ProductFactory pf = null;

    public Producer(ProductFactory pf) {
        this.pf = pf;
    }

    public void run() {
        // 一共生產20個產品
        for(int i=0; i<20; i++) {
            // 隨機產生一個大寫字母作為產品
            Random r = new Random();
            char p = (char)(r.nextInt(26) + 'A');
            try {
                // 產品入庫
                pf.produceProduct(p);
                // 故意sleep,以便消費線程有機會獲得CPU時間片,方便演示
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

// 消費者
class Consumer extends Thread {
    private ProductFactory pf = null;

    public Consumer(ProductFactory pf) {
        this.pf = pf;
    }

    public void run() {
        // 一共消費20個產品
        for(int i=0; i<20; i++) {
            try {
                // 產品出庫
                pf.consumeProduct();
                // 故意sleep,以便生產線程有機會獲得CPU時間片,方便演示
                // sleep時間稍微錯開,阻止同時競爭CPU時間片
                Thread.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved