生产者与消费者模式简单介绍:
生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费。消费者线程从缓冲区中获得物品,然后释放缓冲区。当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者线程释放出一个空缓冲区。当消费者线程消费物品时,如果没有满的缓冲区,那么消费者线程将被阻塞,直到新的物品被生产出来
以示例来说明问题:
以下程序参考至: http://www.iteye.com/topic/256991
首先是产品类:
Java代码 收藏代码
package consumerandproducter;
/**
* 单纯的产品类
* @author google
*
*/
public class Product {
private int productId=0;
public Product(int id){
this.productId=id;
}
public int getProductId() {
return productId;
}
public String toString(){
return "product "+productId;
}
}
再是仓库(缓冲区):
Java代码 收藏代码
package consumerandproducter;
/**
* 模拟缓冲区,以栈为数据结构,先进后出
* @author google
*
*/
public class StoreHouse {
private int base=0;
private int top=0;
private Product[] products=new Product[10];
/**
* 入栈
* @param product
*/
public synchronized void push (Product product) {
while(top==products.length){
//当前的线程已经放弃对资源的占有,唤醒已经被wait的线程,唤醒的线程由JVM决定,不按优先级确定
notify();
try {
System.out.println("仓库已满,正在等待消费……");
wait();//此线程处于等待状态
} catch (Exception e) {
e.printStackTrace();
}
}
products[top]=product;
top++;
}
/**
* 出栈
* @return
*/
public synchronized Product pop(){
Product product=null;
while(top==base){
notify();
try {
System.out.println("仓库已空,正在等待生产……");
wait();
} catch (Exception e) {
e.printStackTrace();
}
}
top--;
product=products[top];
products[top]=null;
return product;
}
}
接着是消费者:
Java代码 收藏代码
package consumerandproducter;
public class Consumer implements Runnable {
private String consumerName;
//保留有缓冲区对象的引用,以便消费产品
private StoreHouse storeHouse;
public Consumer(String consumerName, StoreHouse storeHouse) {
this.consumerName = consumerName;
this.storeHouse = storeHouse;
}
public void run() {
while(true){
System.out.println("消费者"+consumerName+"已经消费"+storeHouse.pop());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public String getConsumerName() {
return consumerName;
}
public void setConsumerName(String consumerName) {
this.consumerName = consumerName;
}
}
然后是生产者:
Java代码 收藏代码
package consumerandproducter;
/**
* 生产者类
* @author google
*
*/
public class Producter implements Runnable {
private String producterName;
// 保留有缓冲区对象的引用,以便将生产的产品放入缓冲区
private StoreHouse storeHouse;
public Producter(String producterName, StoreHouse storeHouse) {
this.producterName = producterName;
this.storeHouse = storeHouse;
}
public String getProducterName() {
return producterName;
}
public void setProducterName(String producterName) {
this.producterName = producterName;
}
public void producterProduct(){
//生产产品,并放入到仓库中
int i=0;
while(true){
i++;
Product product=new Product(i);
storeHouse.push(product);
System.out.println(producterName+"生产了");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
return;
}
}
}
public void run() {
producterProduct();
}
}
测试类:
Java代码 收藏代码
package consumerandproducter;
import sun.security.krb5.internal.crypto.t;
public class Test {
public static void main(String[] args) {
StoreHouse storeHouse=new StoreHouse();
Producter producter=new Producter("生产者",storeHouse);
Consumer consumer=new Consumer("消费者",storeHouse);
Thread t1=new Thread(producter);
Thread t2=new Thread(consumer);
t1.start();
t2.start();
/**
* ~输出(随机抽取输出,每次测试的结果可能都有稍许不同):
*
生产者生产了
消费者消费者已经消费product 1
生产者生产了
消费者消费者已经消费product 2
生产者生产了
消费者消费者已经消费product 3
生产者生产了
消费者消费者已经消费product 4
...........
仓库已空,正在等待生产……
生产者生产了
生产者生产了
生产者生产了
生产者生产了
.........
仓库已满,正在等待消费……
消费者消费者已经消费product 14
消费者消费者已经消费product 13
消费者消费者已经消费product 12
消费者消费者已经消费product 11
消费者消费者已经消费product 10
......
*/
}
}
小结:
此问题主要是考察java间多线程通信与资源同步, 其中主要是对于notify与wait方法的使用上,还有对于线程间资源的共享,利用synchronized关键字,对共享资源的锁定,以达到线程同步的效果。