当前位置 主页 > 服务器问题 > Linux/apache问题 >

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

    栏目:Linux/apache问题 时间:2020-01-26 21:20

    这篇文章主要介绍了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();
      }
    }