Java多线程之生产者-消费者模式

来源:互联网 发布:空间主页图片网络错误 编辑:程序博客网 时间:2024/06/05 12:16

问题描述

假如汽车公司只有一个生产车间, 一间存储仓库(仓库可存储做多n辆车),该公司只生产一种车型。现在需要模仿生产、销售过程。每生产一辆汽车,需要送入仓库临时存储,当仓库满后,停止生产,车辆的销售有一个前提条件是,库存大于零。

问题分析

使用面向对象的思维,我们需要考虑类的设计
生产车间(生产者):生产者生产汽车放入仓库,这个类包括生产汽车和调入指定库存两个方法
消费者:汽车取出仓库,这个类具有取出汽车的方法
仓库:库存数量,这个类需要统计汽车数量,当库存已满或者库存为空是发出消息
数据结构设计
仓库被设计成栈结构
考虑到汽车生产和销售是两个独立的过程,有必要使用多线程

代码描述

public class ProducersConsumers {    public static void main(String[] args) {        Storage storage = new Storage();        Producer producer = new Producer(storage);        Consumer consumer = new Consumer(storage);        new Thread(producer).start();        new Thread(consumer).start();    }}class Car{    int id;   //每辆汽车取一个id    public Car(int id) {        this.id = id;    }}class Storage{    int index;   //用数组实现栈结构    private static final int MAX_NUM = 20;    Car[] carStack = new Car[MAX_NUM];    //入库    public  synchronized void push(Car car){        while (index == MAX_NUM){            try {                this.wait(); //仓库满时,入库线程等待            }catch (InterruptedException e){}        }        this.notify(); //有可能空唤醒        carStack[index] = car;        index++;    }    //出库    public synchronized Car pop( ){        while (index == 0){            try {                this.wait(); //库存为空时,出库线程等待            }catch (InterruptedException e){}        }        this.notify();        index--;        return carStack[index];    }}class Producer implements Runnable{    Storage storage = null;    //每一辆汽车都会放入仓库,本例只有一个仓库    public Producer(Storage storage) {        this.storage = storage;    }    public void run( ) {        for (int i = 0; i < 20; i++) {            Car car = new Car(i);            storage.push(car);            System.out.println("生产了"+i+"辆汽车");            try {                Thread.sleep(100);            }catch (InterruptedException e){}        }    }}class Consumer implements Runnable{    Storage storage = null;    //从仓库取出一辆汽车    public Consumer(Storage storage) {this.storage = storage;}    public void run( ) {        for (int i = 0; i < 20; i++) {            storage.pop();            System.out.println("卖出了"+i+"辆汽车");            try {                Thread.sleep(100);            }catch (InterruptedException e){}        }    }}
上面的问题中,如果存在多个生产者和多个消费者,上面的问题将变得复杂。在这个问题中,最重要的地方在于有多个进程可以访问公共资源,因此首先要考虑进程的同步问题,不能让两个线程交叉执行(在这个例子中可以理解为,汽车入库和出库必须经过一扇很狭小的门,当然实际中并不是这样)。第二个需要考虑的问题是线程之间的通信问题,表现为 线程的等待和唤醒机制。当然,在实际应用中,任何产生数据的程序都可以称为生产者,而删除数据的一方可被视为消费者。
另外,在实际编码中,恰当使用锁的粒度、使用线程池、使用缓冲队列等都是可以提高的地方。



0 0
原创粉丝点击