生产者和消费者模式:这其实是一个线程同步问题,生产者和消费者共享同一个资源,并且生产者和消费者之间相互依赖,互为条件
对于生产者,没有生产产品之前,要通知消费者等待。而生产了产品之后,又需要马上通知消费者消费。
对于消费者,消费之后,要通知生产者已经消费完成,需要继续生产新的产品给消费者消费。
在生产者和消费者问题中,仅有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条)