Java等待唤醒机制原理实例解析

 更新时间:2020年01月20日 15:01:52   作者:LeeHua  
这篇文章主要介绍了Java等待唤醒机制原理实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

这篇文章主要介绍了Java等待唤醒机制原理实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

线程的状态

首先了解一下什么是线程的状态,线程状态就是当线程被创建(new),并且启动(start)后,它不是一启动就进入了执行状态(run),也不是一直都处于执行状态。

这里说一下Java 的Thread类里面有一个State方法,这个方法里面涵盖了6种线程的状态,如下:

public enum State {
  // 尚未启动的线程的线程状态。
  NEW,

  // 可运行线程的线程状态。
  RUNNABLE,

  // 线程的线程状态被阻塞,等待监视器锁定。
  BLOCKED,

  // 等待线程的线程状态。
  WAITING,

  // 具有指定等待时间的等待线程的线程状态。
  TIMED_WAITING,

  // 终止线程的线程状态。
  TERMINATED;
}

导致这六种线程状态发生的条件

New -- 新建

线程刚被创建,不过还没有被启动(还没有调用start方法)

Runnable -- 可运行

处于可运行状态的线程正在Java虚拟机中执行,但是它可能正在等待来自操作系统(例如处理器)的其他资源。

Blocked -- 锁阻塞
当一个线程想获取一个对象锁,不过该对象锁被其它的线程持有时,该线程就会进入锁阻塞状态;当该线程持有锁的时候,该线程将会变成可运行的状态。

Waiting -- 无限等待

当一个线程在等待另一个线程执行一个(唤醒)动作时,该线程就会进入无限等待状态。进入这个状态后是不能自动唤醒的,要等待另一个线程调用notify()方法,或notifyall()方法才能够被唤醒。

Timed_Waiting -- 计时等待

类似于无限等待状态,有几个方法有超时参数,如:Thread.sleep、Object.wait方法。调用这些方法,进入计时等待状态。计时等待状态将会一直保持到超时期满或者接收到唤醒通知。

terminated -- 被终止

1、因为run方法的正常退出而死亡。

2、因为没有捕获的异常,终止了run方法而死亡。

等待唤醒案例切入

顾客要去饭店吃饭,自助下单,说明要吃什么,数量是多少。下完单以后,顾客就等待该饭店厨师做饭菜,也就是Waiting状态(无限等待状态)。

厨师收到下单信息,开始做饭菜,做好饭菜,把饭菜递到顾客桌面上,顾客看到饭菜已经来了(notify方法),就可以开吃了(等待唤醒机制)。

Java代码实现(线程之间的通信)

分析

创建一个顾客线程:下单,告知厨师要什么菜,菜的数量,调用wait方法,放弃CPU的执行,进入到无限等待状态(Waiting)

创建一个厨师线程:看到下单,花了3秒钟做饭菜,做好之后,调用notify方法,唤醒顾客吃饭了。

注意

顾客线程和厨师线程,必须使用同步代码块包裹起来,保证等待和唤醒只能有一个在执行。

同步使用的锁对象必须保证唯一。

只有锁对象才能够调用Object.wait方法和Object.notify方法。

代码

public class Demo01WaitNotify {
  public static void main(String[] args) {
    // 创建锁对象(要保证锁唯一)
    Object object = new Object();

    // 创建一个顾客线程
    new Thread() {
      @Override
      public void run() {
        // 使用同步代码块包裹起来,保证等待和唤醒只能有一个在执行。
        synchronized (object) {
          // 顾客下单
          System.out.println("我要一个西虹市炒番茄,一个马铃薯炒土豆,两碗米饭");
          // 调用wait方法,放弃CPU的执行,进入到无限等待状态(Waiting)
          try {
            object.wait();
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
          // 唤醒之后(饭菜上来后),吃饭!!!真香。
          System.out.println("我就是饿死,从这里跳下去,也不会吃你们一口饭。。。真香!!!!");
        }
      }
    }.start();

    // 创建一个厨师线程
    new Thread() {
      @Override
      public void run() {
        // 厨师收到下单请求,花三秒钟把饭菜做好
        try {
          Thread.sleep(3000);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        // 使用同步代码块包裹起来,保证等待和唤醒只能有一个在执行。
        synchronized (object) {
          System.out.println("我的饭菜三秒钟做好了,你食唔食哦?");
          // 做好之后,调用notify方法,唤醒顾客吃饭了。
          object.notify();
        }
      }
    }.start();
  }
}

控制台输出:

我要一个西虹市炒番茄,一个马铃薯炒土豆,两碗米饭
我的饭菜三秒钟做好了,你食唔食哦?
我就是饿死,从这里跳下去,也不会吃你们一口饭。。。真香!!!!

上面的代码,存在线程间的通信,那什么又是线程间的通信呢?简单的说,就是多个线程在处理同一个资源,但是处理的动作(线程的任务)却不同。如上,厨师线程做饭菜,顾客线程吃饭菜。那为什么要进行线程间的通信呢?多个线程并发执行的时候,在默认情况下CPU是随机切换线程的,当我们需要多个线程来共同完成一件任务,并且希望它们有规律的执行的时候,那么多线程就之间就需要一些协调通信,来达到多线程共同操作一份数据。

对代码中通信的理解:

对又没有饭菜进行判断——

1、没有饭菜(False)。

2、顾客下单。

3、厨师做饭菜。

4、顾客线程等待。

5、厨师做好饭菜

6、修改饭菜的状态(True)

7、有饭菜,厨师线程提醒顾客线程吃饭菜。

8、厨师线程等待

9、吃完饭菜,修改饭菜的状态(False)

这就是顾客线程与厨师线程之间的通信。以此类推,其它Java程序中多线程的通信也是同样的道理。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • SpringBoot Knife4j在线API文档框架基本使用

    SpringBoot Knife4j在线API文档框架基本使用

    knife4j是为Java MVC框架集成Swagger生成Api文档的增强解决方案,这篇文章主要介绍了SpringBoot中使用Knife4J在线API文档框架,需要的朋友可以参考下
    2022-12-12
  • Java实现Excel文件转PDF(无水印无限制)

    Java实现Excel文件转PDF(无水印无限制)

    这篇文章主要为大家详细介绍了如何利用Java语言实现Excel文件转PDF的效果,并可以无水印、无限制。文中的示例代码讲解详细,需要的可以参考一下
    2022-06-06
  • java为什么需要虚拟机jvm原理详解

    java为什么需要虚拟机jvm原理详解

    这篇文章主要为大家介绍了java为什么需要虚拟机jvm的原理详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加薪
    2021-11-11
  • Java 中不全部使用 Static 方法的理由

    Java 中不全部使用 Static 方法的理由

    这篇文章主要介绍了Java 中不全部使用 Static 方法的理由,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-08-08
  • 一文带你掌握java8中的reduce操作

    一文带你掌握java8中的reduce操作

    reduce 操作是一种通用的归约操作,它可以实现从 Stream 中生成一个值,其生成的值不是随意的,而是根据指定的计算模型,下面我们就来深入了解下java8中的reduce操作吧
    2023-12-12
  • Java实现颜色渐变效果

    Java实现颜色渐变效果

    这篇文章主要为大家详细介绍了Java实现颜色渐变效果的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-12-12
  • Java数据结构和算法之冒泡排序(动力节点Java学院整理)

    Java数据结构和算法之冒泡排序(动力节点Java学院整理)

    冒泡排序(Bubble Sort)是一种简单的排序算法。本文重点给大家介绍java数据结构和算法之冒泡排序,非常不错,具有参考借鉴价值,需要的的朋友参考下吧
    2017-04-04
  • Java的设计模式编程中迪米特法则的应用示例

    Java的设计模式编程中迪米特法则的应用示例

    这篇文章主要介绍了Java的设计模式编程中迪米特法则的应用示例,迪米特法则中主张创建和使用弱耦合的类,需要的朋友可以参考下
    2016-02-02
  • Springboot网站第三方登录 微信登录

    Springboot网站第三方登录 微信登录

    这篇文章主要为大家详细介绍了Springboot网站第三方登录 ,微信登录,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-12-12
  • Java经典排序算法之归并排序实现代码

    Java经典排序算法之归并排序实现代码

    这篇文章主要介绍了Java经典排序算法之归并排序实现代码,归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用,将已有序的子序列合并,得到完全有序的序列,需要的朋友可以参考下
    2023-10-10

最新评论