【6.20】sleep()和wait()的区别

news2024/11/24 16:58:56

sleep()和wait()的区别

1、wait()方法

1.1使用场景

当某个线程获取到锁后,却还是不满足执行的条件,就可以调用对象锁的wait方法,进入等待状态。

直到外在条件满足了,就可以由其它线程调用notify或者notifyAll方法,来唤醒这个线程。

1.2条件

只有已经获取锁的线程,才可以调用锁的wait、notify方法,否则会抛出IllegalMonitorStateException异常。

看如下代码:

@Log4j
public class WaitTest {
 
    public static void main(String[] args) {
        Object lock = new Object();
        Thread threadA = new Thread(() -> {
            synchronized (lock) {
                log.info("获取了锁");
                try {
                    log.info("休眠一会儿");
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.info("调用wait..");
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
 
                log.info("被唤醒");
            }
        }, "A");
        threadA.start();
 
        lock.notify();
 
    }
}

输出为:

在这里插入图片描述

这是因为:线程A获得锁之后,主动调用wait方法释放了锁和CPU资源,陷入阻塞状态。主线程在没获得锁的情况下,调用notify方法,会抛出异常。

再看如下代码:

@Log4j
public class WaitTest {
 
    public static void main(String[] args) {
        Object lock = new Object();
        Thread threadA = new Thread(() -> {
            synchronized (lock) {
                log.info("获取了锁");
                try {
                    log.info("休眠一会儿");
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.info("调用wait..");
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
 
                log.info("被唤醒");
            }
        }, "A");
        threadA.start();
 
        Thread threadB = new Thread(()->{
            synchronized (lock) {
                log.info("获得了锁");
 
                log.info("叫醒A");
                lock.notify();
            }
        }, "B");
        threadB.start();
    }
}

输出为:

在这里插入图片描述

这是因为:线程A调用wait方法主动释放锁,线程B获得了锁,调用了notify方法,才能叫醒线程A。

线程正常运行时的状态是Runnable,调用wait方法之后,变为Waiting状态。那么主动Waiting的线程,被唤醒后,状态一定会由Waiting变为Runnable吗?

答案是不一定的。

看如下代码:

@Log4j
public class WaitTest {
 
    public static void main(String[] args) throws InterruptedException {
        Object lock = new Object();
        Thread threadA = new Thread(() -> {
            synchronized (lock) {
                log.info("获取了锁");
                try {
                    log.info("休眠一会儿");
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.info("调用wait..");
                try {
                    log.info("wait前的线程状态" + Thread.currentThread().getState());
                    lock.wait();
                    log.info("wait后的线程状态" + Thread.currentThread().getState());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
 
                log.info("被唤醒");
            }
        }, "A");
        threadA.start();
 
        TimeUnit.SECONDS.sleep(2);
 
        Thread threadB = new Thread(()->{
            synchronized (lock) {
                log.info("获得了锁");
                log.info("叫醒A前,A的状态" + threadA.getState());
                log.info("叫醒A");
                lock.notify();
                log.info("发现还有很多事需要做,先不释放锁");
                log.info("我在做事过程中,A的状态: " + threadA.getState());
                try {
                    TimeUnit.SECONDS.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.info("我做完了");
            }
        }, "B");
        threadB.start();
    }
}

输出为:

在这里插入图片描述

这是因为:线程B调用notify方法后,没有立刻将线程的控制器交出去,线程A被唤醒后,会先变为Blocked,参与锁的竞争,成功竞争到锁后,才会向下执行。

被唤醒的线程需要重新参与锁竞争。

1.2sleep()方法

作用:让当前线程进入指定的休眠时间(单位是毫秒),进入阻塞状态,放弃占有CPU时间片,让给其它线程使用。

public class ThreadTest06 {
    public static void main(String[] args) {
        //让当前线程(主线程)进入休眠,睡眠5秒
        try {
            Thread.sleep(1000*5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

		//5秒之后执行这里的代码
        System.out.println("hello world!");
    }
}

sleep()和wait()的区别

1.sleep属于Thread类;wait属于Object类

2.sleep不会释放锁,也不需要占用锁;wait会释放锁

3.sleep可以在任何地方使用,wait只能在同步方法或同步控制块中使用

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

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

相关文章

在软件研发排期中要求“倒推时间”,项目结束后悲剧了……

有没有遇到某个项目任务的研发周期已被各路boss定下,研发团队都觉得时间不合理,反馈给上级无果,而要求“倒推时间”进行任务排期的情况? 什么是“倒推时间”? 目标倒推法,从剩下的时间反推算出每天该做的事…

【Java】死锁问题及ThreadLocal

什么是死锁分析过程发生死锁的原因避免死锁ThreadLocal 什么是死锁 多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止。这是一个最严重的BUG之一。 分析过程 1.一个线程一把锁 一个线…

深入理解TDD(测试驱动开发):提升代码质量的利器

在日常的软件开发工作中,我们常常会遇到这样的问题:如何在繁忙的项目进度中,保证我们的代码质量?如何在不断的迭代更新中,避免引入新的错误?对此,有一种有效的开发方式能帮助我们解决这些问题&a…

14.处理大数据集

14.1 随机梯度下降 假设你正在使用梯度下降来训练一个线性回归模型 当m个样本的m很大时,求和计算量太大了。这种梯度下降算法有另外一个名字叫做批量梯度下降(batch gradient desent)。这种算法每次迭代需要使用全量训练集,直到算…

【代码阅读软件】Source Insight 4 使用教程 | 很详细——适合新手

目录 一、概述二、常用的几个窗口👉2.1 符号窗口(Symbol Window)👉2.2 项目文件窗口(Project Window)👉2.3 关系窗口(Relation Window)👉2.4 上下文窗口&…

STM32--基于固件库(Library Faction)的led灯点亮

目录 一、STM32芯片的简单介绍 二、基于固件库(Library Faction)的led灯点亮 这是一个学习stm32的开端,我们由简入难,之前学过C51/52或是其他型号的一般都是从led开始,也就是简单的输入输出端口的应用。(想…

SpringBoot整合模板引擎Thymeleaf(1)

版权声明 本文原创作者:谷哥的小弟作者博客地址:http://blog.csdn.net/lfdfhl Thymeleaf概述 Thymeleaf是一种用于Web和独立环境的现代服务器端的Java模板引擎,主要目标是将优雅的自然模板带到开发工作流程中,并将HTML在浏览器中…

【kubernetes】Etcd集群部署与验证

前言:二进制部署kubernetes集群在企业应用中扮演着非常重要的角色。无论是集群升级,还是证书设置有效期都非常方便,也是从事云原生相关工作从入门到精通不得不迈过的坎。通过本系列文章,你将从虚拟机准备开始,到使用二进制方式从零到一搭建起安全稳定的高可用kubernetes集…

吐血整理,性能测试Jmeter分布式压测遇坑总结+解决

目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 为什么要使用分布…

JSON.parse() 全面用法介绍

JSON 通常用于与服务端交换数据。在接收服务器数据时一般是字符串。我们可以使用 JSON.parse() 方法将数据转换为 JavaScript 对象。 语法 JSON.parse(text[, reviver]) text:必需, 一个有效的 JSON 字符串。 reviver: 可选,一个转换结果的函数&#xf…

SPI协议解析

SPI协议介绍 引言介绍SPI简介物理层协议层通讯的起始和停止信号SPI 模式 优缺点优点缺点 使用例程基于STM32的SPI通信准备硬件连接 软件实现 总结 引言 SPI是串行外设接口的缩写,是一种高速的,全双工,同步的通信总线。由于SPI高速和同步的特…

vite环境变量与模式

环境变量 Vite 在一个特殊的 import.meta.env 对象上暴露环境变量。这里有一些在所有情况下都可以使用的内建变量: import.meta.env.MODE: {string} 应用运行的模式。 import.meta.env.BASE_URL: {string} 部署应用时的基本 URL。他由base 配置项决定。 import.m…

【ESP8266】使用MQTT协议 连接华为云iotDA,实现设备属性上报

相关资料:https://github.com/CQUPTLei/ESP8266 往期文章:【ESP8266】基础AT指令和常用WIF指令 【MQTT 5.0】协议 ——发布订阅模式、Qos、keepalive、连接认证、消息结构 一、华为云iotDA1.1 什么是iotDA1.2 创建 iotDA 产品 二、使用ESP8266上报设备…

【杂谈理解】STM32F10X标准库工程模板

前言 基于STM官网的STM32F10x标准外设库V3.6.0版本,文件的操作流程是参考江科大的。记录下此文方便学习和回忆。文章后也会放置完整的工程文件和意法官网下载STM32F10x标准外设库的压缩包。 流程 到意法官网下载STM32F10x标准外设库的压缩包。先找到压缩包的地址&a…

CMake详解

file文件操作 cmake的file命令_cmake file_物随心转的博客-CSDN博客 set指令 CMake中的set指令详解_cmake set_guanguanboy的博客-CSDN博客 include_directories指令 Cmake命令之include_directories介绍 - 简书 add_subdirectory Cmake命令之add_subdirectory介绍 - 简书…

两台电脑用网线传输文件的一些问题解决

两台电脑用网线传输文件 步骤如下: 一、两台电脑插上网线 网线568A和568B可能没什么影响 二、 ipv4地址配置 两个网线插上电脑会自动生成一个ipv4地址 cmd里使用ipconfig查看 用这个就行了如果不想用自动生成的ip地址 也可以自己配置ipv4地址和网关&#xff08…

升级Nginx

目录 前言 一、升级Nginx 1)首先在官网下载一个新版本的Nginx 2)首先将下载的压缩包进行解包 3)进入已解包的目录中 4)配置安装路径 5)make 6)备份原来Nginx的资源 7)重启Nginx服务 8&#…

面向对象程序设计|运算符重载

题目一:分数的加减乘除(运算符重载) 题目描述: Fraction类的基本形式如下: 要求如下: 1.实现Fraction类;common_divisor()和contracted()函数体可为空,不实现具体功能。 2.编写m…

Qt QPainterPath

作用 为painter设置好绘画路径 成员函数 painter.drawPath() 1,使用当前笔画轮廓; 2,填充path指定的路径绘画出来的图形。 xxx.to() lineTo() moveTo() 使用path作画,一定要先将path的启动移动到需要开始绘画的点,否则默认从 (0&…

【大数据之Hive】十三、Hive-HQL函数之单行函数和高级聚合函数

Hive内置函数:单行函数、聚合函数、炸裂函数、窗口函数。 --查看系统内置函数: show functions;--查看内置函数用法: desc function 函数名;--查看内置函数详细信息: desc function extended 函数名;一、单行函数 单行…