介绍
生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区的线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。
关系
生产者:生产者:负责生产数据的模块(可能是方法﹐对象,线程﹐进程);
消费者∶负责处理数据的模块(可能是方法,对象,线程,进程);
缓冲区∶消费者不能直接使用生产者的数据,)他们之间有个“缓冲区
生产者将生产好的数据放入缓冲区,消费者从缓冲区拿出数据
主要使用的方法
代码
管程法
public class ProducerAndConsumer {
public static void main(String[] args) {
//创建货架对象
GoodsShelf goodsShelf = new GoodsShelf();
//生产者消费者都是对一个货架进行操作,所以传参数都一样
Producer producer = new Producer(goodsShelf);
Consumer consumer = new Consumer(goodsShelf);
//开始
new Thread(producer).start();
new Thread(consumer).start();
}
}
//商品
class Iphone{
int number;
public Iphone(int number){
this.number = number;
}
}
//货架
class GoodsShelf{
//可以放10个商品的货架
Iphone[] iphones = new Iphone[10];
//显示货架商品数量
int count = 0;
//对象调用的wait()方法时一定要在同步块或者同步方法中调用,以确保代码段不会被多个线程调用。
public synchronized void pushIphone(Iphone iphone){
//如果货架数量等于货架的最大容量则停止生产
if (count == iphones.length){
try {
System.out.println("=============货架已满============");
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//商品放入货架
iphones[count] = iphone;
//商品数量加1
count++;
//通知消费者可以消费了
this.notifyAll();
}
public synchronized Iphone popIphone(){
//没有商品了等待生产线生产
if (count == 0){
try {
System.out.println("=============货架没有商品了============");
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//产品数量减1。注意:商品的下标等于商品数量减1,所以要先减
count--;
//通知生产者生产
this.notifyAll();
return iphones[count];
}
}
//生产者
class Producer implements Runnable{
private final GoodsShelf goodsShelf;
public Producer(GoodsShelf goodsShelf){
this.goodsShelf = goodsShelf;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
try {
//睡眠0.01秒方便观察。睡眠不释放锁
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
goodsShelf.pushIphone(new Iphone(i));
System.out.printf("生产了%3d号手机\r\n",i);
}
}
}
//消费者
class Consumer implements Runnable{
private final GoodsShelf goodsShelf;
public Consumer(GoodsShelf goodsShelf){
this.goodsShelf = goodsShelf;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
try {
//睡眠
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
Iphone iphone = goodsShelf.popIphone();
System.out.printf("消费了%3d号手机\r\n",iphone.number);
}
}
}
信号灯法
生产者消费者通过标志变量来控制生产和消费
public class ProducerAndConsumer2 {
public static void main(String[] args) {
IPhone iPhone = new IPhone();
new PhoneConsumer(iPhone).start();
new PhoneProducer(iPhone).start();
}
}
//操作的对象
class IPhone{
private int number;
//标志变量
boolean flag = true;
public synchronized void makeAPhone(int number){
if (!flag){
try {
//等待消费者消费
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.number = number;
System.out.println("+生产了"+number+"号手机");
//修改标志变量,并通知消费者消费
this.flag = !this.flag;
this.notifyAll();
}
public synchronized void sellAPhone(){
if (flag){
try {
//等待生产者生产
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("-卖出了"+number+"号手机");
//修改标志变量,并通知生产者生产
this.flag = !this.flag;
this.notifyAll();
}
}
//生产者
class PhoneProducer extends Thread{
IPhone iPhone;
public PhoneProducer(IPhone iPhone){
this.iPhone = iPhone;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
iPhone.makeAPhone(i);
}
}
}
//消费者
class PhoneConsumer extends Thread{
IPhone iPhone;
public PhoneConsumer(IPhone iPhone){
this.iPhone = iPhone;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
iPhone.sellAPhone();
}
}
}
每天进步一点点------------------------------------------------------------------