生产者和消费者问题是线程操作中的一个经典案例,本文采用Java多线程来实现这一经典问题。
1、使用Java来实现,首先要分析这个问题需要几个类来实现:
(1)这个问题本身就是一个类,即主类 ;
(2)要有生产者类和消费者类;
(3)生产什么,消费什么,所以需要一个物品类,这里使用电脑类 ,表示生产和消费电脑;
(4)多线程操作,需要对资源区的资源进行异步操作,即生产的电脑需要一个仓库存放,消费电脑也需要从这个仓库取出来,因此需要一个盛放电脑的仓库类。
2、解决这个问题要注意:
(1)生产者和消费者可能会同时对资源区(仓库)进行异步操作,会导致仓库内电脑数量不一致,因此要使用Java中的synchronized关键字对存放电脑和取出电脑的操作进行同步。
(2)如果仓库已满,则生产者线程阻塞,需要等待;如果仓库为空,则消费者线程阻塞需要等待,因此需要使用Java中的一些线程的等待和唤醒的方法。
public class Procon { //主类
public static void main(String[] args) {
Repertory rep = new Repertory(5);//新建一个存放电脑的仓库
Producer p = new Producer(rep);//新建一个生产者对象,使用rep仓库
Consumer c = new Consumer(rep);//新建一个消费者对象,使用同一个rep仓库
Thread pt = new Thread(p);//生产者线程
Thread ct = new Thread(c);//消费者线程
pt.start();//启动生产者线程
ct.start();//启动消费者线程
}
}
//电脑类
class Computer{
int id;//电脑编号
Computer(int id){
this.id = id;
}
public String getComputer(){
return "Computer:"+this.id;
}
}
//仓库类
class Repertory{
private int length; //仓库大小
private Computer[] compArrey;//具体存放电脑的位置
private int index;//仓库位置的索引
Repertory(int len){
this.length = len;
this.index = 0;
compArrey = new Computer[len];//构造电脑对象数组,在这个仓库中开辟存放电脑的空间
}
//将电脑放入仓库的方法,使用synchronized来保持仓库数据的同步
public synchronized void push(Computer c){
while(this.index == this.length){//如果仓库满了,需要生产者线程等待
try {
this.wait();//让当前线程等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notify();//唤醒在此对象监视器上等待的单个线程,即消费者线程
this.compArrey[index] = c;
this.index++;
}
//从仓库中取出电脑
public synchronized Computer pop(){
while(this.index == 0){//如果仓库为空,需要消费者线程等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notify();
this.index--;
return this.compArrey[index];
}
}
//生产者类实现Runnable接口,用于构造生产者线程
class Producer implements Runnable{
private Repertory rep; //使用的仓库
Producer(Repertory rep){
this.rep = rep;
}
@Override //重写run方法
public void run() {
// 开始生产电脑
for(int i=0;i<10;i++){
Computer c = new Computer(i);
this.rep.push(c);
System.out.println("生产了"+c.getComputer());
try {
Thread.sleep(10);//每生产一台电脑,线程休眠10毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//消费者类实现Runnable接口,用于构造消费者线程
class Consumer implements Runnable{
private Repertory rep; //使用的仓库
Consumer(Repertory rep){
this.rep = rep;
}
@Override
public void run() {
for(int i=0;i<10;i++){//开始消费电脑
Computer c = this.rep.pop();
System.out.println("消费了"+c.getComputer());
try {
Thread.sleep(100);//每消费一台电脑,消费者线程休眠100毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}