iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >java中的wait()和notify()方法实现生产者消费者模式实例
  • 375
分享到

java中的wait()和notify()方法实现生产者消费者模式实例

2023-06-20 19:06:59 375人浏览 薄情痞子
摘要

这篇文章主要介绍“java中的wait()和notify()方法实现生产者消费者模式实例”,在日常操作中,相信很多人在java中的wait()和notify()方法实现生产者消费者模式实例问题上存在疑惑,小编查阅了各式资料,整理出简单好用的

这篇文章主要介绍“java中的wait()和notify()方法实现生产者消费者模式实例”,在日常操作中,相信很多人在java中的wait()和notify()方法实现生产者消费者模式实例问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”java中的wait()和notify()方法实现生产者消费者模式实例”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

java wait()/notify() 实现生产者消费者模式

java中的多线程会涉及到线程间通信,常见的线程通信方式,例如共享变量、管道流等,这里我们要实现生产者消费者模式,也需要涉及到线程通信,不过这里我们用到了java中的wait()、notify()方法:

wait():进入临界区的线程在运行到一部分后,发现进行后面的任务所需的资源还没有准备充分,所以调用wait()方法,让线程阻塞,等待资源,同时释放临界区的,此时线程的状态也从RUNNABLE状态变为WAITING状态;

notify():准备资源的线程在准备好资源后,调用notify()方法通知需要使用资源的线程,同时释放临界区的锁,将临界区的锁交给使用资源的线程。

wait()、notify()这两个方法,都必须要在临界区中调用,即是在synchronized同步块中调用,不然会抛出IllegalMonitorStateException的异常。

实现源码

生产者线程类:
package threads; import java.util.List;import java.util.UUID; public class Producer extends Thread{  private List<String> storage;//生产者仓库 public Producer(List<String> storage) {  this.storage = storage; } public void run(){  //生产者每隔1s生产1~100消息  long oldTime = System.currentTimeMillis();  while(true){   synchronized(storage){    if (System.currentTimeMillis() - oldTime >= 1000) {     oldTime = System.currentTimeMillis();     int size = (int)(Math.random()*100) + 1;     for (int i = 0; i < size; i++) {      String msg = UUID.randomUUID().toString();      storage.add(msg);     }     System.out.println("线程"+this.getName()+"生产消息"+size+"条");     storage.notify();    }   }  } }}
消费者线程类:
package threads; import java.util.List; public class Consumer extends Thread{  private List<String> storage;//仓库 public Consumer(List<String> storage) {  this.storage = storage; } public void run(){  while(true){   synchronized(storage){    //消费者去仓库拿消息的时候,如果发现仓库数据为空,则等待    if (storage.isEmpty()) {     try {      storage.wait();     } catch (InterruptedException e) {      e.printStackTrace();     }    }    int size = storage.size();    for (int i = size - 1; i >= 0; i--) {     storage.remove(i);    }    System.out.println("线程"+this.getName()+"成功消费"+size+"条消息");   }  } }}
仓库类:
package threads; import java.util.ArrayList;import java.util.List; public class Storage {  private List<String> storage;//生产者和消费者共享的仓库 public Storage() {  storage = new ArrayList<String>(); } public List<String> getStorage() {  return storage; } public void setStorage(List<String> storage) {  this.storage = storage; } }
main方法类:
package threads; public class App {  public static void main(String[] args) {  Storage storage = new Storage();  Producer producer = new Producer(storage.getStorage());  Consumer consumer = new Consumer(storage.getStorage());  producer.start();  consumer.start(); }}
生产消费效果:

java中的wait()和notify()方法实现生产者消费者模式实例

Wait/Notify通知机制解析

前言

我们知道,java的wait/notify的通知机制可以用来实现线程间通信。wait表示线程的等待,调用该方法会导致线程阻塞,直至另一线程调用notify或notifyAll方法才可另其继续执行。经典的生产者、消费者模式即是使用wait/notify机制得以完成。在这篇文章中,我们将深入解析这一机制,了解其背后的原理。

线程的状态

在了解wait/notify机制前,先熟悉一下java线程的几个生命周期。分别为初始(NEW)、运行(RUNNABLE)、阻塞(BLOCKED)、等待(WAITING)、超时等待(TIMED_WAITING)、终止(TERMINATED)等状态(位于java.lang.Thread.State枚举类中)。

以下是对这几个状态的简要说明,详细说明见该类注释。

状态名称说明
NEW初始状态,线程被构建,但未调用start()方法
RUNNABLE运行状态,调用start()方法后。在java线程中,将操作系统线程的就绪和运行统称运行状态
BLOCKED阻塞状态,线程等待进入synchronized代码块或方法中,等待获取锁
WAITING等待状态,线程可调用wait、join等操作使自己陷入等待状态,并等待其他线程做出特定操作(如notify或中断)
TIMED_WAITING超时等待,线程调用sleep(timeout)、wait(timeout)等操作进入超时等待状态,超时后自行返回
TERMINATED终止状态,线程运行结束

对于以上线程间的状态及转化关系,我们需要知道

  • WAITING(等待状态)和TIMED_WAITING(超时等待)都会令线程进入等待状态,不同的是TIMED_WAITING会在超时后自行返回,而WAITING则需要等待至条件改变。

  • 进入阻塞状态的唯一前提是在等待获取同步锁。java注释说的很明白,只有两种情况可以使线程进入阻塞状态:一是等待进入synchronized块或方法,另一个是在调用wait()方法后重新进入synchronized块或方法。下文会有详细解释。

  • Lock类对于锁的实现不会令线程进入阻塞状态,Lock底层调用LockSupport.park()方法,使线程进入的是等待状态。

wait/notify用例

让我们先通过一个示例解析

wait()方法可以使线程进入等待状态,而notify()可以使等待的状态唤醒。这样的同步机制十分适合生产者、消费者模式:消费者消费某个资源,而生产者生产该资源。当该资源缺失时,消费者调用wait()方法进行自我阻塞,等待生产者的生产;生产者生产完毕后调用notify/notifyAll()唤醒消费者进行消费。

以下是代码示例,其中flag标志表示资源的有无。

public class ThreadTest {    static final Object obj = new Object();    private static boolean flag = false;    public static void main(String[] args) throws Exception {        Thread consume = new Thread(new Consume(), "Consume");        Thread produce = new Thread(new Produce(), "Produce");        consume.start();        Thread.sleep(1000);        produce.start();        try {            produce.join();            consume.join();        } catch (InterruptedException e) {            e.printStackTrace();        }    }    // 生产者线程    static class Produce implements Runnable {        @Override        public void run() {            synchronized (obj) {                System.out.println("进入生产者线程");                System.out.println("生产");                try {                    TimeUnit.MILLISECONDS.sleep(2000);  //模拟生产过程                    flag = true;                    obj.notify();  //通知消费者                    TimeUnit.MILLISECONDS.sleep(1000);  //模拟其他耗时操作                    System.out.println("退出生产者线程");                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }    }    //消费者线程    static class Consume implements Runnable {        @Override        public void run() {            synchronized (obj) {                System.out.println("进入消费者线程");                System.out.println("wait flag 1:" + flag);                while (!flag) {  //判断条件是否满足,若不满足则等待                    try {                        System.out.println("还没生产,进入等待");                        obj.wait();                        System.out.println("结束等待");                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }                System.out.println("wait flag 2:" + flag);                System.out.println("消费");                System.out.println("退出消费者线程");            }        }    }}

输出结果为:

进入消费者线程

wait flag 1:false

还没生产,进入等待

进入生产者线程

生产

退出生产者线程

结束等待

wait flag 2:true

消费

退出消费者线程

理解了输出结果的顺序,也就明白了wait/notify的基本用法。有以下几点需要知道:

  • 在示例中没有体现但很重要的是,wait/notify方法的调用必须处在该对象的锁(Monitor)中,也即,在调用这些方法时首先需要获得该对象的锁。否则会爬出IllegalMonitorStateException异常。

  • 从输出结果来看,在生产者调用notify()后,消费者并没有立即被唤醒,而是等到生产者退出同步块后才唤醒执行。(这点其实也好理解,synchronized同步方法(块)同一时刻只允许一个线程在里面,生产者不退出,消费者也进不去)

  • 注意,消费者被唤醒后是从wait()方法(被阻塞的地方)后面执行,而不是重新从同步块开头。

深入了解

这一节我们探讨wait/notify与线程状态之间的关系。深入了解线程的生命周期。

由前面线程的状态转化图可知,当调用wait()方法后,线程会进入WAITING(等待状态),后续被notify()后,并没有立即被执行,而是进入等待获取锁的阻塞队列。

对于每个对象来说,都有自己的等待队列和阻塞队列。以前面的生产者、消费者为例,我们拿obj对象作为对象锁,配合图示。内部流程如下

  • 当线程A(消费者)调用wait()方法后,线程A让出锁,自己进入等待状态,同时加入锁对象的等待队列。

  • 线程B(生产者)获取锁后,调用notify方法通知锁对象的等待队列,使得线程A从等待队列进入阻塞队列。

  • 线程A进入阻塞队列后,直至线程B释放锁后,线程A竞争得到锁继续从wait()方法后执行。

到此,关于“java中的wait()和notify()方法实现生产者消费者模式实例”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

--结束END--

本文标题: java中的wait()和notify()方法实现生产者消费者模式实例

本文链接: https://www.lsjlt.com/news/299254.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • java中的wait()和notify()方法实现生产者消费者模式实例
    这篇文章主要介绍“java中的wait()和notify()方法实现生产者消费者模式实例”,在日常操作中,相信很多人在java中的wait()和notify()方法实现生产者消费者模式实例问题上存在疑惑,小编查阅了各式资料,整理出简单好用的...
    99+
    2023-06-20
  • java wait()/notify() 实现生产者消费者模式详解
    java wait()/notify() 实现生产者消费者模式 java中的多线程会涉及到线程间通信,常见的线程通信方式,例如共享变量、管道流等,这里我们要实现生产者消费者模式,也需...
    99+
    2022-11-12
  • Java多线程中消费者生产者模式怎么实现
    这篇文章主要讲解了“Java多线程中消费者生产者模式怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java多线程中消费者生产者模式怎么实现”吧!  //主类&nb...
    99+
    2023-06-17
  • java中生产者和消费者问题实例分析
    这篇“java中生产者和消费者问题实例分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“java中生产者和消费者问题实例分析...
    99+
    2023-06-29
  • Java编程生产者消费者实现的四种方法
    目录实现生产者消费者的四种方式一、最基础的二、java.util.concurrent.lock 中的 Lock 框架三、阻塞队列BlockingQueue的实现Blockqueue...
    99+
    2022-11-12
  • 队列的生产者与消费者模式在PHP与MySQL中的实现方法
    随着互联网业务的快速发展,系统中处理大量任务的需求变得越来越迫切。队列是一种常见的解决方案,可以高效地处理任务。队列的生产者-消费者模式(Producer-Consumer Pattern)在PHP和MySQL中的实现方法是一种常见的解决方...
    99+
    2023-10-21
    MySQL 消费者 PHP 队列 生产者
  • Java实现生产者消费者的两种方式分别是什么
    本篇文章给大家分享的是有关Java实现生产者消费者的两种方式分别是什么,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。   我在8年前去面试程序员的时候,一个...
    99+
    2023-06-03
  • Python中怎么利用多线程实现生产者消费者模式
    Python中怎么利用多线程实现生产者消费者模式,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。什么是生产者消费者模式在软件开发的过程中,经常碰到这样的场景:某些模块负责生产数据...
    99+
    2023-06-17
  • python多进程中的生产者和消费者模型怎么实现
    这篇文章主要介绍了python多进程中的生产者和消费者模型怎么实现的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇python多进程中的生产者和消费者模型怎么实现文章都会有所收获,下面我们一起来看看吧。Pytho...
    99+
    2023-07-05
  • Java实现生产者消费者问题与读者写者问题的示例分析
    这篇文章将为大家详细讲解有关Java实现生产者消费者问题与读者写者问题的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。1、生产者消费者问题生产者消费者问题是研究多线程程序时绕不开的经典问题之一,它...
    99+
    2023-05-30
    java
  • 理解生产者消费者模型及在Python编程中的运用实例
    什么是生产者消费者模型 在 工作中,大家可能会碰到这样一种情况:某个模块负责产生数据,这些数据由另一个模块来负责处理(此处的模块是广义的,可以是类、函数、线程、进程等)。产 生数据的模块,就形象地称为生产者...
    99+
    2022-06-04
    生产者 实例 模型
  • JAVA项目中的生产者消费者如何利用多线程实现
    今天就跟大家聊聊有关JAVA项目中的生产者消费者如何利用多线程实现,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。JAVA多线程实现生产者消费者的实例详解Product.Javapac...
    99+
    2023-05-31
    java 多线程 ava
  • Java多线程Queue、BlockingQueue和使用BlockingQueue实现生产消费者模型方法解析
    Queue是什么队列,是一种数据结构。除了优先级队列和LIFO队列外,队列都是以FIFO(先进先出)的方式对各个元素进行排序的。无论使用哪种排序方式,队列的头都是调用remove()或poll()移除元素的。在FIFO队列中,所有新元素都插...
    99+
    2023-05-30
    java 多线程 生产消费者
  • 在Java项目中实现装饰者模式的方法
    在Java项目中实现装饰者模式的方法?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。装饰模式在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对...
    99+
    2023-05-31
    java 装饰者模式 ava
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作