多线程-线程的等待通知wait、notify

news2024/10/5 14:43:46

目录

1.什么是线程的等待通知

2.wiat()方法

    2.1 wait 做的事情:

2.2wait 结束等待的条件:

代码示例:

 2.3wait的三种重载方式

2.4 面试问题:wait()和sleep()之间的区别

3.notify()方法

3.1notify ⽅法是唤醒等待的线程.

 3.2wait 和notify之间的联系

 3.3notifyAll()


1.什么是线程的等待通知

        线程的等待通知是多线程编程中常用的一种机制,用于线程之间的协作和同步。在Java中,线程的等待通知通过使用wait()notify()notifyAll()方法来实现。

         由于线程之间是抢占式执⾏的, 因此线程之间执⾏的先后顺序难以预知. 但是实际开发中有时候我们希望合理的协调多个线程之间的执⾏先后顺序,所以我们需要wait()、notify()来实现这些功能。

2.wiat()方法

    2.1 wait 做的事情:

使当前执⾏代码的线程进⾏等待. (把线程放到等待队列中)
释放当前的锁
满⾜⼀定条件时被唤醒, 重新尝试获取这个锁.
注意:wait 要搭配 synchronized 来使⽤. 脱离 synchronized 使⽤ wait 会直接抛出异常.

2.2wait 结束等待的条件:

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

代码示例:

package 多线程;

public class ThreadDemo18 {
    public static void main(String[] args) throws InterruptedException {
        Object object = new Object();//new一个对象
        synchronized (object){//对对象进行加锁
            System.out.println("等待中···");
            object.wait();//当前线程会释放对象的锁,并进入等待状态。
            System.out.println("等待结束。");
        }
    }
}

       主线程会打印"等待中···",然后调用object.wait()方法,释放对象的锁,并进入等待状态。当其他线程调用了object.notify()object.notifyAll()方法时,主线程会被唤醒,然后重新获取对象的锁,并继续执行输出"等待结束。"。但是这个代码种没有notify()方法,所以没有重新唤起线程,就没有输出等待结束。

 

 2.3wait的三种重载方式

        第一种wait()重载方式:它是死等的,就是说如果没有notify()方法来唤醒它,它就一直处于阻塞状态。

        第二种wait()重载方式:它自己设定了一个超时的时间,单位是ms。就是说它最多等待到设定的时间,在这个时间内没有notify也不等了,直接会被唤醒。

       第三种wait()重载方式:方法使当前线程进入等待状态,直到其他线程调用该对象notify()notifyAll()方法唤醒它,或者指定的超时时间到达。这个方法允许设置纳秒级别的超时时间,除了毫秒级别的参数外,还可以指定纳秒级别的增量。

2.4 面试问题:wait()和sleep()之间的区别

   wait提供了一个带超时间的版本   

    sleep也是可以指定时间        都是时间到了解除阻塞。

wait和sleep都是可以提前被唤醒的

wait通过notify()来唤醒

sleep通过interrupt来唤醒

使用wait的主要目的,一定是不知道要等多少时间的前提下来使用的。所谓的超时间,其实是“兜底的”。

使用sleep,一定是知道要等多长时间,必须要等到那个时间才会被唤醒。 

3.notify()方法

3.1notify ⽅法是唤醒等待的线程.

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

 代码示例:

package 多线程;

public class ThreadDemo19 {
    public static void main(String[] args) {
        //需要一个统一的对象进行加锁,wait,notify
        Object locker = new Object();
        
        Thread t1 = new Thread(()->{
            synchronized (locker){
                System.out.println("t1 wait 之前");
                try {
                    locker.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("t1 wait 之后");
            }
        });
        Thread t2 = new Thread(()->{
            try {
                Thread.sleep(5000);
            synchronized (locker){
                System.out.println("t2 notify 之前");
                    locker.notify();
                System.out.println("t2 notify 之后");
                } 
                }
            catch (InterruptedException e) {
                e.printStackTrace();
                
            }
        });
    }
}

 1) t1 执行起来之后,就会先立即拿到锁,并且打印t1 wait 之前,并进入wait 方法(释放锁+阻塞等待)

2) t2 执行起来之后,先进行 sleep(5000)(这个 sleep 就可以让t1 能够先拿到锁)

3) t2 sleep 结束之后,由于t1 是wait 状态,锁是释放的.t2 就能拿到锁
接下来打印t2 notify 之前,执行 notify 操作,这个操作就能唤醒t1.(此时t1 就从 WAITING状态恢复回来了)

4)但是由于 t2 此时还没有释放锁呢,t1 WAITING 恢复之后,尝试获取锁,就可能出现一个小小的阻塞.

5) t2执行完 t2-motify 之后,释放锁,t2执行完毕.

所以输出结果如下:

 3.2wait 和notify之间的联系

wait 和notify之间是通过Object对象联系起来的。

Object1.wait()

Object2.notify() 此时如果用notify是无法被唤醒的,必须是两个对象一样才能唤醒。

Object1.wait()

Object2.wait()此时notify使用的哪个对象,哪个对象才能被唤醒。

 3.3notifyAll()

         唤醒这个对象上所有等待的线程.假设有很多个线程,都使用同一个对象 wait.针对这个对象进行 notifyAII,此时就会全都唤醒~~但是注意,这些线程在wait返回的时候,要重新获取锁,就会因为锁的竞争,使这些线程实际上是一个一个串行执行的.

具体使用方式如下:

  1. notifyAll()方法必须在同步代码块或同步方法中调用,并且只能应用于被synchronized关键字修饰的对象上。

  2. 当调用对象的notifyAll()方法时,该对象上所有等待的线程都会被唤醒,并尝试重新获取对象的锁。

  3. 被唤醒的线程会进入就绪状态,然后根据线程调度机制竞争获取锁。

  4. 只有获取到对象的锁的线程才能继续执行同步代码块中的内容,而其他未获取到锁的线程仍然处于阻塞状态,直到再次获得锁的机会。

希望大家多多支持! 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1405233.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CHS_03.2.2.3_1+2.2.5+进程调度的时机、切换与过程、方式

CHS_03.2.2.3_12.2.5进程调度的时机、切换与过程、方式 知识总览进程调度的时机进程调度的方式进程的切换与过程 知识回顾 在这个小节中 我们会继续学习进程调度相关的一系列知识点 知识总览 首先 我们会来回答下 进程调度的时机是什么 什么时候需要进行进程调度 而什么时候又…

docker 搭建mysql集群一主一从,两台机器

一、准备两条机器,分别为IP1和IP2,其中IP1为主,IP2为从 二、在两台机器上分别拉取mysql镜像 docker pull mysql:8.0.29三、在home目录下新建目录,分别为/home/mysql/data,/home/mysql/conf 1、在IP1主机下的/home/mysql/conf目录下新建my.cn…

日期处理第四篇(终)- Java日期时间处理大总结

文章目录 日期时间概念通用标准日期字段解析国际化的日期格式 日期的实战第一个问题:日期常用时间操作第二个问题:时区的问题时区概念时区的处理ZoneID的使用 ZoneOffset的使用让人恼火的夏令时 第三个问题:MySQL存储时间用什么类型&#xff…

12. openCV在QT环境中利用zBar开发库实现二维码内容识别

1. 说明 本篇博客仅记录如何使用zBar库进行二维码内容的识别,其中牵扯到的一些其它知识点,比如二维码区域检测、zBar库开发环境配置等可以参考本专栏的其它相关博客,此篇博客不再赘述。 2. 具体步骤 博客中代码功能:手动选择一张包含二维码的图片,会将检测到的二维码区…

Linux 的提示符太长了,帮你精简一下

普通用户修改文件 ~/.bashrc 修改 50 行左右的代码,将两个w改为大写的W 如果是root用户则修改文件/root/.bashrc,同样的方法。

Lingo数学建模基础

1.基本运算符 1.1算数运算符 1.2逻辑运算 #not# 否定操作数的逻辑值,一元运算符 #eq# 若两运算数相等,则为true,否则为false #ne# 若两运算数不相等,则为true,否则为false #gt# 若左边运算数严格大于右边,则为true,否则为…

智能小程序环境配置流程

App 与智能小程序 在用户使用 App 扫描小程序的二维码或者点击设备,尝试进入小程序时,系统会对 App 当前环境与小程序所需运行环境进行比对,确定环境配置兼容后,App 才能启动并运行小程序。 比对规则中,主要涉及&…

NVMe TCG安全数据存储简介

NVMe(非易失性内存主机控制器接口规范)与TCG(可信计算组)的集成主要体现在数据安全、固件验证和硬件信任根等方面,以确保存储设备的数据保护能力和安全性。 TCG Opal定义了一套针对自加密硬盘(SED, Self-En…

Linux部署MinIO实现图片存储,读取,删除

1、MinIo简介 MinIO 是一个高性能的分布式对象存储服务,它与亚马逊的S3(简单存储服务)兼容,在开源许可下是免费和开放的。您可以用它存储任何种类的对象,也就是说可以存储无结构的数据如照片、视频、日志文件、备份和…

解决github无法访问的问题(修改hosts)

1.先ping github.com看是否能ping通 不能ping通的话,找到github最新的ip地址,修改hosts文件(C:\Windows\System32\drivers\etc) 找最新的ip地址的办法: a.cmd中ping时返回的 b.点击ipaddress.com查询网站链接 修改host…

c盘红色满了怎么清理c盘空间?整理了5个方法~

用户文档、下载文件、图片和视频等个人文件的不断增长导致了磁盘空间紧张。那么如何管理文件,清理我们的电脑呢?下面整理了5个不同类型的方法。 方法一:清理临时文件 1、打开“运行”(Win R),输入 %temp…

最新阿里云免费SSL证书申请使用介绍

为网站部署SSL证书已经是现在站长的必须要做的工作,然而SSL证书并不全是免费的,免费且好用的资源也越来越有限,毕竟嘛,这些都需要成本。 PS:最下方有最终建议方案。 本文介绍当前(2024年)阿里云免费SSL证书信息。 阿…

企业为什么需要WMS仓储管理系统,终于有人说明白了

随着科技的飞速发展和市场竞争的加剧,仓储企业面临着越来越多的挑战和机遇。为了提高产品的性能和质量,同时节约成本、提高运营效率,数字化建设成为了仓储企业的核心需求。而WMS仓储管理系统的应用,更是企业数字化建设的重中之重。…

jdk的安装和Tomcat的安装

jdk的安装 双击jdk,然后一路下一步 公共JRE可以关闭,没多大用,反而会占用内存 计算机–>属性–>高级系统设置–>环境变量 系统变量–新建 JAVA_HOMEjdk的存放路径 修改path 在path的最后面添加(;%JAVA_H…

springboot 整合 ElasticSearch 方法 (一)

下载 ES 相当于安装 MySQL, 可以在官网上下载 (链接在后面). 要注意安装的 ES 的版本要和项目中用的 Springboot 的版本对应. 比如我用的 Springboot 版本是 2.6, 所以ES要下载7.15 版本的. 官网链接: https://www.elastic.co/cn/downloads/elasticsearch 点右边这个查看更多…

视频监控平台EasyCVR增加fMP4流媒体视频格式及其应用场景介绍

近期我们在视频监控管理平台EasyCVR系统中新增了HTTP-FMP4播放协议,今天我们就来聊聊该协议的特点和应用。 fMP4(Fragmented MPEG-4)是基于MPEG-4 Part 12的流媒体格式,是流媒体的一项重要技术,因为它能通过互联网传送…

Nuxt2.x Error页面返回自定义请求状态码

一、问题描述 最近接到一个需求,针对Nuxt2.x的一个项目进行SEO优化,需要对404页面的状态进行修改,将404页面的请求状态码改为301,而不是404: 二、解决方案 1.几种无效尝试 (1)layouts下的err…

InternLM第6次课笔记

OpenCompass 大模型评测 测评什么 如何评测 基座模型:加入instrcut 对话模型:直接对话 评测方式 客观 主观 提示词工程 不同prompt鲁棒性 OpenCompass能力框架

Portainer Docker容器可视化管理平台实践

Portainer Docker容器可视化管理平台实践 引安装登录Remote ENV 实践 引 平常用docker命令操作比较多,找了一款docker可视化工具,方便快速预览和批量操作,不想一行一行敲的时候,可以偷偷懒。Portainer试用了一下,安装…

实施企业增长战略:明确需求和战略咨询公司选择尤为重要

在当今快速变化的商业环境中,企业的增长并非偶然产生的成果,而是通过精心设计和策略性规划实现的。企业要实现增长,明确企业自身需求和选择专业的战略咨询公司是非常重要的。接下来,本文就这两大关键问题进行分析。首先&#xff0…