1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > Java并发编程系列18:多线程之生产者和消费者模式_信号灯法(wait/notify通知机制)

Java并发编程系列18:多线程之生产者和消费者模式_信号灯法(wait/notify通知机制)

时间:2020-08-08 16:18:51

相关推荐

Java并发编程系列18:多线程之生产者和消费者模式_信号灯法(wait/notify通知机制)

1、生产者消费者模式

生产者消费者问题(Producer-consumer problem),也称为有限缓冲问题(Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了两个共享大小缓冲区的线程---既所谓的“生产者”和“消费者”----在实际运行时会发生的问题。生产者的主要作用时生成一定量的数据放到缓冲区中,然后重复此过程。以此同时,消费者也在缓冲区消费这些数据。该问题的关键是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消费数据。

要解决这些问题,就必须让生产者在缓冲区满时休眠(要不干脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。统一,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者。如果解决办法不够完善,则容易出现死锁的情况。出现死锁时,两个线程都会陷入休眠,等待对方唤醒自己。

生产者和消费者模式:这其实是一个线程同步问题,生产者和消费者共享同一个资源,并且生产者和消费者之间相互依赖,互为条件

对于生产者,没有生产产品之前,要通知消费者等待。而生产了产品之后,又需要马上通知消费者消费。

对于消费者,消费之后,要通知生产者已经消费完成,需要继续生产新的产品给消费者消费。

在生产者和消费者问题中,仅有synchronizede是不够的

synchronized可阻止并发更新同一个共享资源,实现了同步

synchronized不能用来实现不同线程之间的消息传递(通信)

线程通信:并发协助模型“生产者/消费者模式”->可用信号灯法。

2、信号灯法

信号灯法判断生产者(消费者)是否能能够放入(取出)产品的依据是标志位。

设置一个标识,当标识为真的时候,消费者消费,生产者等待。当标识为假的时候,生产者生产,消费者等待.

Java提供了3个方法(java.lang.Object类的方法)解决线程之间的通信问题

方法名:这些方法只能放在同步里。

final void wait() 作用:表示线程一直等待,直到其他线程通知,与sleep不同,会释放锁。

final void wait(long timeout) 作用:指定等待的毫秒数

final void notify() 作用:唤醒一个处于等待状态的线程

final void notifyAll() 作用:唤醒同一个对象上所有调用wait()方法的线程,优先级别搞得线程优先调度。

3、Object的wait/notify+信号灯法代码示例

package runnable;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/*** 一个场景,共同的资源* 生产这消费者模式,信号灯法* wait():等待,释放锁,sleep不释放锁* notify()/notifyAll():唤醒*/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();//信号灯设置为falsethis.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();//设置信号灯为truethis.flag=true;}}//生产者class Maker implements Runnable{public Tea tea;public Maker(Tea tea){this.tea=tea;}@Overridepublic 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;}@Overridepublic void run() {for(int i=0;i<10;i++){tea.Take();}}}//多线程执行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();}}

在使用线程的wait()等待/notify()通知机制时,一般都要配合一个 boolean 变量值(或者其他能够判断真假的条件),在 notify 之前改变该 boolean 变量的值,保证了程序的正确性。

执行结果:

参考:一篇文章,让你彻底弄懂生产者--消费者问题 - 简书 ()

生产者消费者模式-Java实现 - 天目山电鳗 - 博客园 ()

Java 多线程详解(四)------生产者和消费者 - YSOcean - 博客园 ()

JAVA多线程之生产者消费者模型_L_R-CSDN博客_多线程生产者消费者

生产者、消费者问题(管程法与信号灯法) - 墨染念颖 - 博客园 ()

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。