Welcome 微信登录

首页 / 软件开发 / JAVA / 再谈线程:生产者与消费者

再谈线程:生产者与消费者2011-10-07 blogjava Liver场景描述:

一个仓库,生产者在工厂里生产了产品后,将产品存放到仓库里,仓库存放数量有限,当满仓后,停 止生产,直到有消费着将产品消费后才继续生产;消费者从仓库里提取产品,当仓库空仓时,停止消费产 品,直到仓库中有产品时,才继续消费产品。

代码的实现(调整线程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();
}
}
}
}