特别是在初级开发的面试中,面试官可能会让我们实现一个生产者消费者线程,因为这个模型其实能考查到比较多的基础知识,比如多线程、栈、设计模式等等之类的。拿到这个问题,其实我们的第一反应是不难,但是要立刻写出来又感觉无从下手,因为要实现这个模型,其实过程还是比较繁琐的,代码量相比其他算法来说也大一些,可能有些初级开发者没有真正理解到这个模型的情况下,其实是背的代码,因为上述原因,时间久了肯定忘了代码怎么实现的,所以感觉自己会,就是写不出来?。
下面我以面包的生产、消费过程为例,引用生活中的例子,添加通俗易懂的注释,为大家实现一下这个模型,我觉得大家完全可以就按照面包的生产、消费过程来理解这个模型,其实就很好理解了,今后自己实现的时候也可以按照这个过程将代码实现出来:
package com.zhangdeshuai;
/**
* 说明:生产作者消费者模型中需要有这些对象:生产者、消费者、面包、装面包的容器-盘子(栈结构),所以创建一个生产者消费者模型需要创建以下类:
* 1、消费生产标的物类,即面包 Bread
* 2、模拟栈类,即盘子 Plate
* 3、生产者类 Product
* 4、消费者类 Consum
* 5、主函数类,创建线程启用生产者、消费者
* @author 章德帅
*
*/
public class ProductionAndConsumption {
public static void main(String[] args) {
Plate plate = new Plate(); //创建面包盘
Product product = new Product(plate); //创建生产者,生产者需要拿到面包盘用来装面包
Consum consum = new Consum(plate); //创建消费者,消费者需要拿到面包盘从中取面包
Thread productThread = new Thread(product); //创建生产者线程,使用线程创建的第二种方式
Thread consumThread = new Thread(consum); //创建消费者线程,使用线程创建的第二种方式
//启用线程
productThread.start();
consumThread.start();
}
}
/*
* 生产消费标的物:面包Bread类
*/
class Bread{
int num;
Bread(int num){//new Bread(i)时调用构造方法注入num,标注这是第几个面包
this.num = num;
}
public String toString(){//重写toString()是为了打印出这是第几个面包
return "第"+num+"个面包";
}
}
/*
* 创建盘子Plate类装面包(栈结构),需要实现装入和取出的方法
*/
class Plate{
int index;
Bread [] breads = new Bread[5]; //首先定义盘子大小,一盘能装5个面包
//装入面包
public synchronized void push(Bread bread){
while(index == breads.length){//当index=5时说明这已经是第六个面包了,盘子已经装不下了,要等待消费者取出面包
try {
this.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
this.notify();//唤醒在此对象监视器上等待的单个线程,即生产者线程
breads[index] = bread;
index++;
}
//取出面包
public synchronized Bread pop(){
while(index == 0){//当index=0时说明盘子里已经没有面包可以取了,要等待生产者装入面包
try {
this.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
this.notify();//唤醒在此对象监视器上等待的单个线程,即消费者线程
return breads[--index];//因为在装入后执行了index++,但breads[index++]位置上还没有面包,所以先--index才能取到当前面包
}
}
/*
* 生产者Product类
*/
class Product implements Runnable{
Plate plate = null;
Bread bread = null;
Product(Plate plate){
this.plate = plate; //生产者拿到别人递来的盘子
}
@Override
public void run() {
for(int i=0;i<20;i++){
bread = new Bread(i); //生产者生产面包
plate.push(bread); //生产者将生产的面包放进盘子
System.out.println("生产者生产了:"+bread);
try {
Thread.sleep(10);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
/*
* 消费者Consum类
*/
class Consum implements Runnable{
Plate plate = null;
Bread bread = null;
Consum(Plate plate){
this.plate = plate;//消费者拿到别人递来的面包盘
}
@Override
public void run() {
for(int i=0;i<20;i++){
bread = plate.pop();//消费者从盘子里拿出一个面包
System.out.println("消费者消费了:"+bread);
try {
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}