
生产者和消费者模式:这其实是一个线程同步问题,生产者和消费者共享同一个资源,并且生产者和消费者之间相互依赖,互为条件
对于生产者,没有生产产品之前,要通知消费者等待。而生产了产品之后,又需要马上通知消费者消费。
对于消费者,消费之后,要通知生产者已经消费完成,需要继续生产新的产品给消费者消费。
在生产者和消费者问题中,仅有synchronizede是不够的
synchronized可阻止并发更新同一个共享资源,实现了同步
synchronized不能用来实现不同线程之间的消息传递(通信)
线程通信:并发协助模型“生产者/消费者模式”->信号灯法。
生产者消费者问题(Producer-consumer problem),也称为有限缓冲问题(Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了两个共享大小缓冲区的线程---既所谓的“生产者”和“消费者”----在实际运行时会发生的问题。生产者的主要作用时生成一定量的数据放到缓冲区中,然后重复此过程。以此同时,消费者也在缓冲区消费这些数据。该问题的关键是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消费数据。
要解决这些问题,就必须让生产者在缓冲区满时休眠(要不干脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。统一,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者。如果解决办法不够完善,则容易出现死锁的情况。出现死锁时,两个线程都会陷入休眠,等待对方唤醒自己。
以下是:使用Object的wait/notify的消息通知机制Java提供了3个方法(java.lang.Object类的方法)解决线程之间的通信问题
方法名:这些方法只能放在同步里。
final void wait() 作用:表示线程一直等待,直到其他线程通知,与sleep不同,会释放锁。
final void wait(long timeout) 作用:指定等待的毫秒数
final void notify() 作用:唤醒一个处于等待状态的线程
final void notifyAll() 作用:唤醒同一个对象上所有调用wait()方法的线程,优先级别搞得线程优先调度。
package runnable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class Tea{
private String teaName; //奶茶
//信号灯
//flag=T,生产者生产,消费者等待,生产完成后通知消费。
//flag-F,消费者消费,生产者等待,消费完成后通知生产。
boolean flag=true; //信号灯
public synchronized void Make(String teaName){
if(!flag){ //生产者等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//制作奶茶
System.out.println(Thread.currentThread().getName()+",奶茶店制作了:"+teaName);
this.teaName=teaName; //制作完成
//通知消费者
this.notifyAll();
//信号灯设置为false
this.flag=false;
}
public synchronized void Take(){
if(flag){ //消费者等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//消费者消费
System.out.println(Thread.currentThread().getName()+",消费者拿走了:"+teaName);
//通知生产者
this.notifyAll();
//设置信号灯为true
this.flag=true;
}
}
//生产者
class Maker implements Runnable{
public Tea tea;
public Maker(Tea tea){
this.tea=tea;
}
@Override
public void run() {
for(int i=0;i<10;i++){
if (i%2==0){
this.tea.Make("珍珠奶茶");
}else{
this.tea.Make("香草奶茶");
}
}
}
}
//消费者
class Taker implements Runnable{
public Tea tea;
public Taker(Tea tea){
this.tea=tea;
}
@Override
public void run() {
for(int i=0;i<10;i++){
tea.Take();
}
}
}
在使用线程的wait()等待/notify()通知机制时,一般都要配合一个 boolean 变量值(或者其他能够判断真假的条件),在 notify 之前改变该 boolean 变量的值,保证了程序的正确性。
2.1、new Thread()方式调用//多线程执行
public class TeaTrading {
public static void main(String[] args){
//共同的资源
Tea tea=new Tea();
//生产者和消费者对象,使用同样的资源
Maker marker=new Maker(tea);
Taker taker=new Taker(tea);
new Thread(marker).start();
new Thread(taker).start();
}
}
执行结果:
2.2、线程池方式调用//多线程执行
public class TeaTrading {
public static void main(String[] args){
//共同的资源
Tea tea=new Tea();
//生产者和消费者对象,使用同样的资源
//通过线程池执行
int threadNum=5;
ExecutorService service = Executors.newFixedThreadPool(threadNum);
for(int i=0;i
执行结果:
参考:一篇文章,让你彻底弄懂生产者--消费者问题 - 简书 (jianshu.com)
生产者消费者模式-Java实现 - 天目山电鳗 - 博客园 (cnblogs.com)
Java 多线程详解(四)------生产者和消费者 - YSOcean - 博客园 (cnblogs.com)
JAVA多线程之生产者消费者模型_L_R-CSDN博客_多线程生产者消费者
生产者、消费者问题(管程法与信号灯法) - 墨染念颖 - 博客园 (cnblogs.com)
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)