多线程JUC 第2季 wait和notify唤醒机制

一 wait和notify的区别与相同

1.1 wait和notify的作用

1) 使用wait()、notify()和notifyAII()时需要先对调用对象加锁。否则直接调用的话会抛出 IllegalMonitorStateExceptiona。
2) 调用wait()方法后,线程状态。由RUNNING变为WAITING,并将当前线程放置到对象的等待队列。
3) notify()或notifyAlI()方法调用后,等待线程依旧不会从wait()返回,需要调用notify()或notifAII()的线程释放锁之后,等待线程才有机会从wait()返回。
这点比较重要,就是说执行完对象的notify方法后,当前线程并不是马上释放锁,而是等到执行完synchronized代码段之后才释放锁。
4) notify()方法将等待队列中的一个等待线程从等待队列中移到同步队列中,而notifyAII()方法则是将等待队列中所有的线程全部移到同步队列,被移动的线程状态由WAITING变为 BLOCKED。
5) 从wait()方法返回的前提是获得了调用对象的锁。

1.2 wait和sleep的区别

a)相同点

 sleep 方法和 wait 方法都是用来将线程进入休眠状态的,并且 sleep 和 wait 方法都可以响应 interrupt 中断,也就是线程在休眠的过程中,如果收到中断信号,都可以进行响应并中断,且都可以抛出 InterruptedException 异常。

b)不同点

1.wait 方法必须配合 synchronized 一起使用,不然在运行时就会抛出IllegalMonitorStateException 的异常;而sleep 可以单独使用,无需配合 synchronized 一起使用。

2.wait 方法属于 Object 类的方法,而 sleep 属于 Thread 类的方法

3. sleep 方法具有主动唤醒功能,而不传递任何参数的 wait 方法只能被动的被唤醒

sleep 方法必须要传递一个超时时间的参数,且过了超时时间之后,线程会自动唤醒。而 wait 方法可以不传递任何参数,不传递任何参数时表示永久休眠,直到另一个线程调用了 notify 或 notifyAll 之后,休眠的线程才能被唤醒。

https://mp.weixin.qq.com/s/VwnSAPkvfKa1KnUBNmF7Cg

4.wait 方法会主动的释放锁,而 sleep 方法则不会。

5.调用 sleep 方法线程会进入 TIMED_WAITING 有时限等待状态,而调用无参数的 wait 方法,线程会进入 WAITING 无时限等待状态

1.3 案例演示

1.说明

在调用了 sleep 之后,在主线程里尝试获取锁却没有成功,只有 sleep 执行完之后释放了锁,主线程才正常的得到了锁,这说明 sleep 在休眠时并不会释放锁。

结论:sleep不会释放锁。

2 代码

package com.ljf.thread.shengchenxiaofei;

import java.time.LocalDateTime;

/**
 * @ClassName: DengdaiHuanxing
 * @Description: TODO
 * @Author: admin
 * @Date: 2024/03/17 20:47:45 
 * @Version: V1.0
 **/
public class DengdaiHuanxing {
    public static void main(String[] args) throws InterruptedException {
       test1();
    }
    public static void test1() throws InterruptedException {
        Object obj = new Object();
        new Thread(() -> {
            synchronized (obj) {
                System.out.println("=======子线程获取到锁:" + LocalDateTime.now());
                try {
                    // 休眠 2s
                    Thread.sleep(2000);
                    System.out.println("=======子线程获释放锁:" + LocalDateTime.now());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        // 等新线程先获得锁
        Thread.sleep(200);
        System.out.println("主线程尝试获取锁:" + LocalDateTime.now());
        // 在新线程休眠之后,尝试获取锁
        synchronized (obj) {
            System.out.println("主线程获取到锁:" + LocalDateTime.now());
        }
    }
}

3.结果

1.4 案例演示

1.说明

当调用了 wait 之后,主线程立马尝试获取锁成功了,这就说明 wait 休眠时是释放锁的

2.代码

package com.ljf.thread.shengchenxiaofei;

import java.time.LocalDateTime;

/**
 * @ClassName: DengdaiHuanxing
 * @Description: TODO
 * @Author: admin
 * @Date: 2024/03/17 20:47:45 
 * @Version: V1.0
 **/
public class DengdaiHuanxing {
    public static void main(String[] args) throws InterruptedException {
       test1();
    }
    public static void test1() throws InterruptedException {
        Object obj = new Object();
        new Thread(() -> {
            synchronized (obj) {
                System.out.println("=======子线程获取到锁:" + LocalDateTime.now());
                try {
                    // 休眠 2s
                  //  Thread.sleep(2000);
                    obj.wait(2000);
                    System.out.println("=======子线程获释放锁:" + LocalDateTime.now());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        // 等新线程先获得锁
        Thread.sleep(200);
        System.out.println("主线程尝试获取锁:" + LocalDateTime.now());
        // 在新线程休眠之后,尝试获取锁
        synchronized (obj) {
            System.out.println("主线程获取到锁:" + LocalDateTime.now());
        }
    }
}

3.结果:当调用了 wait 之后,主线程立马尝试获取锁成功了,这就说明 wait 休眠时是释放锁的

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

wordpress子比主题7.6美化插件及新手零基础搭建教程源码下载

版权申请:本文A5资源网原创,经原创作者允许转载许可声明。下载地址http://a5.org.cn/a5_ziyuan/39172.html 本源码由网友在某宝二十几元购买,现分享给大家。下图为源码文件及演示图,安装教程比较详细新手零基础就可搭建 子比主…

NeRF——基于神经辐射场的三维场景重建和理解

概述 三维重建是一种将物理世界中的实体转换为数字模型的计算机技术。其基本概念是通过对物理世界中的物体或场景进行扫描或拍摄,并使用计算机算法将其转换为三维数字模型。抽象意义上的三维模型指的是:形状和外观的组合,并且可以渲染成不同…

【Redis知识点总结】(四)——如何保证缓存与数据库中的数据一致性

Redis知识点总结(四)——如何保证缓存与数据库中的数据一致性 更新缓存删除缓存先删除缓存后更新数据库先更新数据库后删除缓存 使用canal总结 面试会经常遇到这种问题:你们如何保证缓存与数据库中的数据一致性?或者是&#xff1a…

小白必看的Python基础之函数篇

函数最重要的目的是方便我们重复使用相同的一段程序。 将一些操作隶属于一个函数,以后你想实现相同的操作的时候,只用调用函数名就可以,而不需要重复敲所有的语句。 函数的定义 首先,我们要定义一个函数, 以说明这个函数的功能…

把软件加入开机自启动

注意这个方法最佳效果是适用于打开软件后,关闭窗口不会停止服务 例如 nginx 1.把nginx的快捷方式放到如图所示的文件夹下 C:\Users\KIA_27\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup 注意KIA_27应改为你自己的用户名

从政府工作报告探计算机行业发展——探索计算机行业发展蓝图

目录 前言 一、政策导向与行业发展 (一)政策导向的影响 (二)企业如何把握政策机遇推动创新发展 二、技术创新与产业升级 三、数字经济与数字化转型 四、国际合作与竞争态势 五、行业人才培养与科技创新 (一&a…

KubeSphere集群安装-nfs分布式文件共享-对接Harbor-对接阿里云镜像仓库-遇到踩坑记录

KubeSphere安装和使用集群版 官网:https://www.kubesphere.io/zh/ 使用 KubeKey 内置 HAproxy 创建高可用集群:https://www.kubesphere.io/zh/docs/v3.3/installing-on-linux/high-availability-configurations/internal-ha-configuration/ 特别注意 安装前注意必须把当前使…

【十】【算法分析与设计】滑动窗口(1)

209. 长度最小的子数组 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其总和大于等于 target 的长度最小的 连续 子数组 [nums(l), nums(l1), ..., nums(r-1), nums(r)] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。 …

[嵌入式系统-40]:龙芯1B 开发学习套件 -10-PMON启动过程start.S详解

目录 一、龙芯向量表与启动程序的入口(复位向量) 1.1 复位向量: 1.2 代码执行流程 1.3 计算机的南桥 VS 北桥 二、PMON代码执行流程 三、Start.S详解 3.1 CPU初始化时所需要的宏定义 (1)与CPU相关的一些宏定义…

[游戏开发][UE5.3]GAS学习心得

GAS(GameplayAbilitySystem) UE提供的一套技能框架,这个框架也不是万能的,甚至各个部件你要进行封装开发,但这也比你从头写一套技能框架要容易很多。 GAS功能极其强大,所以它是一个庞大的系统,如果想运用得当&#x…

深度学习pytorch——基本运算(持续更新)

基本运算——加、减、乘、除 建议直接使用运算符,函数和运算符的效果相同 代码演示: #%% # 加减乘除 a torch.rand(3,4) b torch.rand(4) # 这里a、b可以相加,别忘了pytorch的broadcast机制 print(ab) print(torch.add(a,b)) print(torc…

MySQL中的索引失效情况介绍

MySQL中的索引是提高查询性能的重要工具。然而,在某些情况下,索引可能无法发挥作用,甚至导致查询性能下降。在本教程中,我们将探讨MySQL中常见的索引失效情况,以及它们的特点和简单的例子。 1. **索引失效的情况** …

代码算法训练营day9 | 28. 实现 strStr() 、459.重复的子字符串

day9: 28. 实现 strStr()KMP的主要应用:什么是前缀表:前缀表是如何记录的: 如何计算前缀表:构造next数组:1、初始化2、处理前后缀不相同的情况3、处理前后缀相同的情况 代码: 459.重复的子字符串…

Python入门(三)

序列 序列是有顺序的数据集合。序列包含的一个数据被称为元素,序列可以由一个或多个元素组成,也是可以没有任何元素的空序列。 序列的类型 元组(定值表):一旦建立,各个元素不可再更变,所以一…

Linux文件操作

pwd命令 cd命令 ls命令 mkdir命令 同时创建父子目录 cp命令 mv命令(相当于用cp复制之后,把源文件删除) 用mv命令来冲命令 rm命令 可以看到,我们用当前目录的文件覆盖了目标路径上的文件,并且目标路径中多了一个以波浪…

5 张图带你了解分布式事务 Saga 模式中的状态机

大家好,我是君哥。 状态机在我们的工作中应用非常广泛,今天聊一聊分布式事务中间件 Seata 中 Saga 模式的状态机。 1 状态机简介 状态机是一个数学模型,它将工作中的运行状态和流转规则抽象出来,可以协调相关信号来完成预先设定…

构造-析构-拷贝构造-赋值运算符重载-const成员函数

1. 类的6个默认成员函数 如果一个类中什么成员都没有,简称为空类。 空类中真的什么都没有吗?并不是,任何类在什么时候都不写时,编译器会自动生成以下6个成员函数。 默认成员函数:用户没有显式实现,编译器…

C++之deque与vector、list对比分析

一.deque讲解 对于vector和list,前一个是顺序表,后一个是带头双向循环链表,前面我们已经实现过,这里就不再讲解了,直接上deque了。 deque:双端队列 常见接口大家可以查看下面链接: deque - …

STM32第九节(中级篇):RCC(第一节)——时钟树讲解

目录 前言 STM32第九节(中级篇):RCC——时钟树讲解 时钟树主系统时钟讲解 HSE时钟 HSI时钟 锁相环时钟 系统时钟 SW位控制 HCLK时钟 PCLKI时钟 PCLK2时钟 RTC时钟 MCO时钟输出 6.2.7时钟安全系统(CSS) 小结 前言 从…

单链表操作

单链表操作 1. 链表的概念2. 链表的分类2.1.单向或者双向2.2 带头或者不带头2.3 循环或者非循环2.4 常用的链表 3. 单链表的实现3.1 单链表的打印3.2 单链表的头插3.3 单链表的尾插3.4 单链表的头删3.5 单链表的尾删3.6 单链表的查询3.7 在pos前插入数据3.8 在pos后插入数据3.9…