我的编程空间,编程开发者的网络收藏夹
学习永远不晚

wait 和 notify

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

wait 和 notify

请添加图片描述

✨个人主页:bit me👇
✨当前专栏:Java EE初阶👇
✨每日一语:阅己,越己,悦己;自行,自省,自醒;无味,无谓,无畏。

目 录

⏰一. wait 和 notify 的引入

由于线程之间是抢占式执行的, 因此线程之间执行的先后顺序难以预知. 但是实际开发中有时候我们希望合理的协调多个线程之间的执行先后顺序.

wait 和 notify 相比于 join 能更好的控制线程之间的执行顺序

  • wait (等待):让当前线程进入等待状态
  • notify (通知/唤醒):唤醒对应的 wait 线程。(从阻塞状态唤醒到就绪状态)

注意: wait, notify都是 Object 类的方法.

  • 使用 o1.notify() 就可以唤醒调用 o1.wait 的线程!!
  • 使用 o2.notify() 是不可以唤醒调用 o1.wait 的线程!

 

⏲二. wait()方法和notify()方法

对于 wait 来说,内部的执行过程还有点小麻烦

  1. 释放锁

wait 一上来就得释放锁,,得在调用 wait 之前,先拿到锁,wait 必须要放到 synchronized 中使用,synchronized 加锁的对象必须是和调用 wait 方法的对象是同一个对象,还得和调用 notify 的对象是同一个对象!!!

  1. 等待通知

  2. 当通知到达之后,就会被唤醒,并且尝试重新获取锁

wait 结束等待的条件:

  • 其他线程调用该对象的 notify 方法.
  • wait 等待时间超时 (wait 方法提供一个带有 timeout 参数的版本, 来指定等待时间).
  • 其他线程调用该等待线程的 interrupted 方法, 导致 wait 抛出 InterruptedException 异常

代码示例: 观察wait()方法使用

public class Demo17 {    public static void main(String[] args) throws InterruptedException {        Object object = new Object();        synchronized (object) {            System.out.println("wait 之前");            object.wait();            System.out.println("wait 之后");        }    }}

在这里插入图片描述

notify 方法是唤醒等待的线程

  • 方法notify()也要在同步方法或同步块中调用,该方法是用来通知那些可能等待该对象的对象锁的其它线程,对其发出通知notify,并使它们重新获取该对象的对象锁。
  • 如果有多个线程等待,则有线程调度器随机挑选出一个呈 wait 状态的线程。(并没有 “先来后到”)
  • 在notify()方法后,当前线程不会马上释放该对象锁,要等到执行notify()方法的线程将程序执行完,也就是退出同步代码块之后才会释放对象锁。

举例实现 wait 和 notify 的内部执行过程:创建两个线程 一个线程调用 wait,一个线程调用 notify

public class Demo18 {//这个对象用来做锁对象public static Object locker = new Object();public static void main(String[] args) {    //用来取等待    Thread waitTask = new Thread(()->{        synchronized (locker) {            try {                System.out.println("wait 开始");                locker.wait();                System.out.println("wait 结束");            } catch (InterruptedException e) {                e.printStackTrace();            }        }    });    waitTask.start();    //创建一个用来通知 / 唤醒的线程    Thread notifyTask = new Thread(()->{       //让用户来控制,用户输入某个内容之后,再执行通知        Scanner scanner = new Scanner(System.in);        System.out.println("输入任意内容,开始通知:");        //next 会阻塞,直到用户真正输入内容以后        scanner.next();        synchronized (locker){            System.out.println("notify 开始");            locker.notify();            System.out.println("notify 结束");        }    });    notifyTask.start();}}

执行过程及结果:

在这里插入图片描述

线程 1 需要先计算一个结果,线程 2 来使用这个结果,线程 2 就可以 wait ,线程 1 计算完结果之后,notify ,唤醒线程 2。

  • wait 和 notify 机制,还能有效避免 "线程饿死"。(有些情况下,调度器可能分配不均匀,导致有些线程反复占用 CPU,有些线程始终捞不着 CPU)

例如:

多个线程抢占一个锁,一个线程 A 抢到了,其他线程排队等待,但是抢到锁的线程 A 却无法完成任务,占着锁不放,导致其他锁也不能干活儿,于是这个线程 A 决定释放锁出来,在外面等待,给其他的锁一些机会,由于线程之间在系统里的调度是随机的,可能下次又是线程 A 进来了,于是多次情况下都是线程 A 占用了 CPU,其他线程都碰不到,导致线程饿死,旱的旱死,涝的涝死。

因此使用 wait 和 notify 就可以解决上述问题,让后面的多个线程拿到锁之后判定当前任务是否可以执行,如果能就干活,不能就进行 wait !wait 来等待合适的时候(条件满足)再继续执行 / 再参与竞争锁

拓展:

  • 线程进入了 WAITING 状态,则务必要其他线程来主动唤醒
  • 线程进入了 BLOCKED 状态,这个则是其他线程把锁释放之后,操作系统来负责唤醒
  • 线程进入了 TIMED_WAITING 状态,操作系统会计时,时间到了之后进行唤醒

这三个阻塞的状态,都会导致 PCB 进入内核队列中对应的阻塞队列。操作系统内核是不区分这三个的状态的!这三个状态是 JVM 中的状态,操作系统内核中衡量线程的状态是另外的方式,没有 JVM 里面的这么细。

notify方法只是一次唤醒某一个等待线程. 使用notifyAll方法可以一次唤醒所有的等待线程.

 

⏱三. wait 和 sleep 的对比(面试题)

其实理论上 wait 和 sleep 完全是没有可比性的,因为一个是用于线程之间的通信的,一个是让线程阻塞一段时间,唯一的相同点就是都可以让线程放弃执行一段时间

他们俩都会让线程进入阻塞,阻塞的原因和目的不同,进入的状态也不同,被唤醒的条件也不一样。

实际开发中会很少使用 sleep ,目的是为了 “放权” ,暂时让出当前 CPU 的使用权。之所以 sleep 使用的少,等待的时间太固定了,要是有突发情况想提前唤醒并不是那么容易,wait 就用的比较多了,wait 可以进行死等,也能设置最长等待时间(涵盖了 sleep 的功能)

1. wait 需要搭配 synchronized 使用. sleep 不需要.
2. wait 是 Object 的方法 sleep 是 Thread 的静态方法.

来源地址:https://blog.csdn.net/m0_67660672/article/details/129505822

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

wait 和 notify

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

下载Word文档

猜你喜欢

2023-09-21

JavaEE中volatile、wait和notify详解

这篇文章主要给大家介绍了关于JavaEE中volatile、wait和notify的相关资料,文中通过实例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
2023-02-03

java多线程wait()和notify()如何使用

小编给大家分享一下java多线程wait()和notify()如何使用,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!注:wait()和notify()应当用在synchronized内package com.test;im
2023-06-02

怎么在Java中正确使用wait, notify和notifyAll

这篇文章将为大家详细讲解有关怎么在Java中正确使用wait, notify和notifyAll,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。wait, notify 和 notifyAll,这些在多线程
2023-06-17

Java多线程wait()和notify()方法详细图解

wait()和notify()是直接隶属于Object类,也就是说所有对象都拥有这一对方法,下面这篇文章主要给大家介绍了关于Java多线程wait()和notify()方法详细图解的相关资料,需要的朋友可以参考下
2022-11-13

Java多线程死锁问题详解(wait和notify)

线程之间形成相互等待资源的环时,就会形成顺序死锁,下面这篇文章主要给大家介绍了关于Java多线程死锁问题(wait和notify)的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
2023-01-05

如何使用wait() 和notify() 机制来完成睡眠和踢

今天就跟大家聊聊有关如何使用wait() 和notify() 机制来完成睡眠和踢,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。使用 wait() 和 notify() 机制来完成“睡
2023-06-03

浅谈Java线程间通信之wait/notify

Java中的wait/notify/notifyAll可用来实现线程间通信,是Object类的方法,这三个方法都是native方法,是平台相关的,常用来实现生产者/消费者模式。先来我们来看下相关定义:wait() :调用该方法的线程进入WA
2023-05-31

Java 中Object的wait() notify() notifyAll()方法使用

Java 中Object的wait() notify() notifyAll()方法使用一、前言  对于并发编程而言,除了Thread以外,对Object对象的wati和notify对象也应该深入了解其用法,虽然知识点不多。二、线程安全基本
2023-05-31

java并发中wait notify notifyAll的示例分析

这篇文章主要介绍java并发中wait notify notifyAll的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、前言java 面试是否有被问到过,sleep 和 wait 方法的区别,关于这个问题
2023-06-15

Java中怎么正确使用wait-notify方法

本篇内容介绍了“Java中怎么正确使用wait-notify方法”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1. sleep(long n
2023-06-29

Java中怎么使用wait和notify实现线程间的通信

这篇“Java中怎么使用wait和notify实现线程间的通信”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Java中怎么使
2023-06-30

JUC中的wait与notify方法实现原理详解

这篇文章主要介绍了JUC中的wait与notify方法实现原理,在进行wait()之前,就代表着需要争夺Synchorized,而Synchronized代码块通过javap生成的字节码中包含monitor enter和monitor exit两个指令
2023-03-10

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录