美文网首页
五 异常与多线程——第四节 等待唤醒机制

五 异常与多线程——第四节 等待唤醒机制

作者: 杜艳_66c4 | 来源:发表于2022-06-05 19:07 被阅读0次

1、线程状态概述

6种状态

2、等待唤醒案例分析

Timed waiting 计时等待

Timed waiting

blocked 阻塞

blocked

waiting

通信

3、等待唤醒案例代码实现

package exception2.waitandnotify;

/**
 * created by apple on 2020/6/27
 * 等待唤醒案例:线程之间的通信
 * 创建一个顾客线程,消费者,告知老板要的包子的种类和数量,调用wait方法,放弃cpu的执行,进入waiting状态,无限等待
 * 创建一个老板线程,生产者,花了5s做包子,做好包子之后,调用notify方法,唤醒顾客,吃包子。
 
注意事项:
 1、顾客和老板线程,使用同步代码块包裹起来,保证等待和唤醒只能有一个在执行
 2、同步使用的锁对象,保证唯一
 3、只有锁对象,才能调用wait和notify方法,

 *Object类中的方法:
 *  void wait(),在其他线程调用此对象的notify()或notifyAll()方法前,导致当前线程等待
 *  void notify(),唤醒在此对象监视器上等待的单个线程,会继续执行wait()方法之后的代码
 *
 */
public class demo01waitandnotify {
    public static void main(String[] args) {
        //创建锁对象,保证唯一
        Object obj = new Object();
        //创建一个顾客线程
        //匿名内部类
        new Thread(){
           //重写run方法,
            @Override
            public void run() {
               //保证等待和唤醒的线程只有一个在执行,需要使用同步机制
                synchronized (obj){
                    System.out.println("告知老板要的包子的种类和数量");
                    //调用wait方法,放弃cpu的执行,进入waiting状态,无限等待
                    try {
                        obj.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //唤醒之后执行的代码
                    System.out.println("包子已经做好,开吃");
                }
            }
        }.start();
        //创建老板线程,
        new Thread(){
            @Override
            public void run() {
                //花了5s做包子
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //保证等待和唤醒的线程只有一个在执行,需要使用同步机制
                synchronized (obj){
                    System.out.println("老板5s之后做好包子,告知顾客,可以吃包子");
                    //,调用notify方法,唤醒顾客,吃包子。
                    obj.notify();
                }
            }
        }.start();
    }
}

4、Object类中wait带参方法和notify方法

  • 进入TimeWaiting(计时等待), 两种方式
    1、使用sleep(Long m)方法,在毫秒值结束之后,线程睡醒进入到Runnable/Blocked状态
    2、使用wait(Long m)方法,如果在毫秒值结束之后,还没有被notify唤醒,会自动醒来,线程睡醒进入Runnable/Blocked状态

  • 唤醒的方法:
    void()notify():唤醒在此对象监视器上等待的单个线程
    void()notifyall() :所有线程

package exception2.waitandnotify;

/**
 * created by apple on 2020/6/27
 
 */
public class Demo02waitAndNotify {
    public static void main(String[] args) {
        //创建锁对象,保证唯一
        Object obj = new Object();
        //创建一个顾客线程
        //匿名内部类
        new Thread(){
            //重写run方法,
            @Override
            public void run() {
                //保证等待和唤醒的线程只有一个在执行,需要使用同步机制
                synchronized (obj){
                    System.out.println("顾客一告知老板要的包子的种类和数量");
                    //调用wait方法,放弃cpu的执行,进入waiting状态,无限等待
                    try {
                        obj.wait(5000); //没人叫醒,自己醒了。
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //唤醒之后执行的代码
                    System.out.println("包子已经做好,顾客一开吃");
                }
            }
        }.start();
        //创建一个顾客线程
        //匿名内部类
        new Thread(){
            //重写run方法,
            @Override
            public void run() {
                //保证等待和唤醒的线程只有一个在执行,需要使用同步机制
                synchronized (obj){
                    System.out.println("顾客二告知老板要的包子的种类和数量");
                    //调用wait方法,放弃cpu的执行,进入waiting状态,无限等待
                    try {
                        obj.wait(5000); //没人叫醒,自己醒了。
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //唤醒之后执行的代码
                    System.out.println("包子已经做好,顾客二开吃");
                }
            }
        }.start();
        //创建老板线程,
        new Thread(){
            @Override
            public void run() {
                //花了5s做包子
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //保证等待和唤醒的线程只有一个在执行,需要使用同步机制
                synchronized (obj){
                    System.out.println("老板5s之后做好包子,告知顾客,可以吃包子");
                   // obj.notify();  如果有多个等待线程,随机唤醒一个
                    //,调用notify方法,唤醒顾客,吃包子。唤醒所有等待线程,
                    obj.notifyAll();  //
                }
            }
        }.start();
    }
}

5、线程间通信

5.1 概念:多个线程在处理同一个资源,但处理的动作(线程的任务)不同。
比如:生产包子。吃包子
5.2 为什么要处理线程间通信
多个线程并发执行时 ,默认情况CPU 随机切换线程,当需要多个线程共同完成一件任务, 并且希望有规律的执行,那多线程之间需要一些通信,以达到多线程共同操作一份数据
方式: 等待唤醒机制

6、 等待唤醒机制概述

多个线程间协作机制


等待唤醒中的方法

重点:有效利用资源

7、 等待唤醒机制需求分析

等待唤醒机制分析需要的类

8、 等待唤醒机制代码实现——包子类& 包子铺

根据上面的图,创建包子类

package con.day13.demo05.Thread.ThreadWait;

public class BaoZi {
    /*
    资源类:包子类
    属性 皮,馅, 状态
     */
    String pi;
    String xian;
    boolean flag = false;
}

包子铺

package con.day13.demo05.Thread.ThreadWait;

import jdk.nashorn.internal.ir.CallNode;

public class BaoZiPu extends Thread{
    /*
    生成者。
    注意:
    1、包子铺和包子的关系通信关系,互斥关系,必须使用同步技术,保证两个线程只有一个在执行
    2、锁对象保证唯一, 可以使用包子对象作为锁对象
    3、包子铺类和吃货类就需要把包子对象作为参数传递过来,
        1、需要在成员位置创建一个包子变量
        2、使用带参数构造方法,为包子变量赋值
     */
    //1、需要在成员位置创建一个包子变量
    private BaoZi bz;
   //2、使用带参数构造方法,为包子变量赋值
    public BaoZiPu (BaoZi bz) {
        this.bz = bz;
    }

    @Override
    public void run() {
        //定义一个变量
        int count = 0;
        //让包子铺一直生产包子
        while (true){
            //必须同步技术保证两个线程只能有一个在执行
            synchronized (bz){
                //对包子的状态进行判断
                if (bz.flag == true){
                    //有包子,包子铺调用wait方法进入等待状态
                    try {
                        bz.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //没有包子,包子铺生成包子,增加趣味性,交替生成两种包子
                if (count %2 == 0){
                    //生产薄皮 三鲜包子
                    bz.pi = "薄皮";
                    bz.xian = "三鲜";
                }else{
                    //生产厚皮,牛肉馅包子
                    bz.pi = "厚皮";
                    bz.xian = "牛肉馅";
                }
                count++;
                System.out.println("包子铺正在生产" + bz.pi+ bz.xian + "的包子");
                //生产需要3s
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //生产完包子。修改包子状态为true
                bz.flag = true;
                //唤醒吃货线程
                bz.notify();
                System.out.println("包子铺已经生产好了" + bz.pi + bz.xian + "可以开始吃了");
            }
        }


    }
}

9、 等待唤醒机制代码实现——吃货类&测试

根据上面的图,创建吃货类,

package con.day13.demo05.Thread.ThreadWait;

public class Chihuo extends Thread{
    //1、需要在成员位置创建一个包子变量
    private BaoZi bz;
    //2、使用带参数构造方法,为包子变量赋值
    public Chihuo (BaoZi bz) {
        this.bz = bz;
    }
 //设置线程任务,吃包子
    @Override
    public void run() {
        //使用死循环,让吃货一直吃包子
        while (true){
            synchronized (bz){
                //对包子状态进行判断
                if (bz.flag = false){
                    //没包子,吃货调用wait方法进入等待状态
                    try {
                        bz.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }else {
                    //被唤醒后,执行代码,吃包子
                    System.out.println("吃货吃" + bz.pi + bz.xian + "包子");
                    //吃货吃完,修改状态
                    bz.flag = false;
                    //吃货唤醒包子铺线程,
                    bz.notify();
                    System.out.println("吃货已经把" + bz.pi + bz.xian + "包子吃完了");
                }

            }
        }
    }
}

测试类:

package con.day13.demo05.Thread.ThreadWait;

public class DemoC {
    public static void main(String[] args) {
        //创建包子对象
        BaoZi bz = new BaoZi();
        //创建包子铺线程,开始生产包子
        new BaoZiPu(bz).start();
        //创建吃货线程,开始吃包子
        new Chihuo(bz).start();
    }
}

相关文章

  • 五 异常与多线程——第四节 等待唤醒机制

    1、线程状态概述 2、等待唤醒案例分析 Timed waiting 计时等待 blocked 阻塞 waiting...

  • JavaSE第19篇:多线程下篇

    核心概述:本篇我们将继续学习Java中的多线程,其中有多线程的等待唤醒机制、Condition接口的使用、Java...

  • Java学习Day13

    今日学习内容总结 线程 等待唤醒机制 线程 多线程原理 多线程执行时,在栈内存中,其实每一个执行线程都有一片自己所...

  • Java学习笔记 23 - 线程之多线程安全、死锁、同步机制

    本文主要内容1、多线程安全问题2、等待唤醒机制 01线程安全 A:线程安全问题引发多线程并发访问同一个数据资源时,...

  • JUC中线程之间得通信

    使用synchronized实现线程间通信,线程间通信:1、生产者+消费者2、通知等待唤醒机制.多线程编程模板:1...

  • Android 学习流程

    1、java * 基础语法 * 面向对象 * 集合 * 多线程 * 异常 异常机制原理 自定义异常 * 输入、输出...

  • 7.线程池、Lambda表达式

    主要内容 等待与唤醒案例 线程池 Lambda表达式 第一章 等待唤醒机制 1.1 线程间通信 概念:多个线程在处...

  • 线程间通信

    线程间通信 等待唤醒机制 等待唤醒机制就是用于解决线程间通信的问题的,使用到的3个方法的含义如下:wait():告...

  • 6.AQS(抽象同步帮助器)

    加锁的本质是什么?加锁的本质是为了在多线程情况下串行的访问临界资源。 一、JAVA中的等待唤醒机制 1.1 基于m...

  • Java多线程间通信

    1.多线程之等待与通知机制1.1什么是等待通知机制?在生活中,如我们去饭店,服务员拿菜单给我们点菜,然后记录完告诉...

网友评论

      本文标题:五 异常与多线程——第四节 等待唤醒机制

      本文链接:https://www.haomeiwen.com/subject/cvqvfktx.html