多线程中sleep、yield、join的用法及sleep与wait区别

2023-11-17

Object中的wait、notify、notifyAll,可以用于线程间的通信,核心原理为借助于监视器的入口集与等待集逻辑

通过这三个方法完成线程在指定锁(监视器)上的等待与唤醒,这三个方法是以锁(监视器)为中心的通信方法

除了它们之外,还有用于线程调度、控制的方法,他们是sleep、yield、join方法,他们可以用于线程的协作,他们是围绕着线程的调度而来的

sleep方法

有两个版本的sleep方法,看得出来,核心仍旧是native方法

非native方法只是进行了参数校验,接着仍旧是调用的native方法,这个情形与wait是类似的

你能说出多线程中sleep、yield、join的用法及sleep与wait区别?

 

接下来仔细看下,native版本的sleep

在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。该线程不丢失任何监视器的所属权。

注意:

sleep不会释放锁,不会释放锁,不会释放锁

可以理解为他进入监视器这个房间之后,在这房间里面睡着了

与wait类似的是,sleep也是可中断方法(从方法签名可以看得出来,可能抛出InterruptedException),也就是说如果一个线程正在sleep,如果另外的线程将他中断(调用interrupt方法),将会抛出异常,并且中断状态将会擦除

所以对于sleep方法,要么自己醒来,要么被中断后也会醒来

对于sleep始终有一个超时时间的设置,所以,尽管他是在监视器内睡着了,但是并不会导致死锁,因为他终究是要醒来的

如下,线程休眠500毫秒,主线程50毫秒打印一次状态

ps:sleep方法的调用结果为状态:TIMED_WAITING

你能说出多线程中sleep、yield、join的用法及sleep与wait区别?

 

借助于sleep方法,可以模拟线程的顺序执行

比如下面示例,两个阶段,第二个阶段将在第一个阶段执行之后才会执行

你能说出多线程中sleep、yield、join的用法及sleep与wait区别?

 

你能说出多线程中sleep、yield、join的用法及sleep与wait区别?

 

另外,你应该已经注意到sleep方法都有static修饰,既然是静态方法,在Thread中的惯例就是针对于:当前线程,当前线程,当前线程

yield方法

对于sleep或者wait方法,他们都将进入特定的状态,伴随着状态的切换,也就意味着等待某些条件的发生,才能够继续,比如条件满足,或者到时间等

但是yield方法不涉及这些事情,他针对的是时间片的划分与调度,所以对开发者来说只是临时让一下,让一下他又不会死,就只是再等等

yield方法将会暂停当前正在执行的线程对象,并执行其它线程,他始终都是RUNNABLE状态

你能说出多线程中sleep、yield、join的用法及sleep与wait区别?

 

不过要注意,可以认为yield只是一种建议性的,如果调用了yield方法,对CPU时间片的分配进行了“礼让”,它仍旧有可能继续获得时间片,并且继续执行

所以一次调用yield 并不一定会代表肯定会发生什么

你能说出多线程中sleep、yield、join的用法及sleep与wait区别?

 

借助于while循环以及yield方法,可以看得出来,也能一定程度上达到线程排序等待的效果

你能说出多线程中sleep、yield、join的用法及sleep与wait区别?

 

yield也是静态方法,所以,也是针对于当前线程,当前线程,当前线程。

join方法

三个版本的join方法

你能说出多线程中sleep、yield、join的用法及sleep与wait区别?

 

方法的实现过程,与wait也是非常类似,下面两个版本的方法一个调用join(0),一个参数校验后,调用join(millis),所以根本还是单参数版本的join方法

你能说出多线程中sleep、yield、join的用法及sleep与wait区别?

 

在方法深入介绍前先看个例子

一个线程,循环5次,每次sleep 1s,主线程中打印信息

从结果可以看到,主线程总是在线程执行之后,才会执行,也就是主线程在等待我们创建的这个线程结束,结束了之后才会继续进行

你能说出多线程中sleep、yield、join的用法及sleep与wait区别?

 

你能说出多线程中sleep、yield、join的用法及sleep与wait区别?

 

如果调整下顺序--->start 与 join的先后顺序,再次看下情况,可以发现顺序没有保障了

你能说出多线程中sleep、yield、join的用法及sleep与wait区别?

 

结论:

主线程main中调用启动线程(调用start),然后调用该线程的join方法,可以达到主线程等待工作线程运行结束才执行的效果,并且join要在start调用后

如何做到的?

你能说出多线程中sleep、yield、join的用法及sleep与wait区别?

 

从上面源代码可以看得出来,内部调用了wait方法,所以也能明白为啥join也会抛出InterruptedException了吧

主线程main中调用thread.join()方法,join方法相当于join(0),也就是

while (isAlive()) {

wait(0);

}

而这个wait(0)就相当于是this.wait(0),this就是我们自己创建的那个线程thread,看看方法的签名是不是有一个synchronized

isAlive()也是this.isAlive(),也就是如果当前线程alive(已经启动,但是未终止),那么将持续等待,等待的临界资源就是我们创建的这个线程对象本身

所以这两行代码的含义就是:

该线程是否还存活?如果存活,调用join的那个线程将会在这个对象上进行等待(进入该线程对象的等待集)

也就是说调用一个线程的join方法,就是在这个线程是等待,这个线程对象就是我们的锁对象(不要疑惑,Object都可以作为锁,Thread实例对象怎么不可以?)

肯定大家很奇怪,既然是等待,wait又不会自己醒来,那不是出问题了吗?

其实线程结束后,会调用this.notifyAll,所以主线程main会被唤醒

 

如果传递的参数不为0,将会走到下面的分支,或wait指定时长,与上面的逻辑一致,只不过是有指定超时时长而已

long delay = millis - now;

if (delay <= 0) {

break;

}

wait(delay);

now = System.currentTimeMillis() - base;

 

手动版本的等待结束

只是将join方法换成了同步代码块,锁对象为那个线程的实例对象thread,调用他的wait方法

从结果上看,效果一样

(不过此处没有持续监测isAlive(),所以一旦主线程醒来,即使线程没有结束,也会继续,不能百分百确保main肯定等待线程结束)

你能说出多线程中sleep、yield、join的用法及sleep与wait区别?

 

不过要注意:注释中有说明,自己不要使用Thread类的实例对象作为锁对象,如果是现在这种场景,使用join即可

为什么?从我们目前来看,join方法就是以这个对象为锁,如果你自己在使用,又是wait又是notify(notifyAll)的,万一出现什么隐匿的问题咋办?

你能说出多线程中sleep、yield、join的用法及sleep与wait区别?

 

所以join方法的原理就是:将指定的Thread实例对象作为锁对象,在其上进行同步,只要那个线程还活着,那么就会持续等待(或者有限时长)

线程终止之后会调用自身this.notifyAll,以通知在其上等待的线程

简单说,只要他活着大家就都等着, 他死了会通知,所以效果就是在哪里调用了谁的join,哪里就要等待这个线程结束,才能继续

为什么要在start之后?

你能说出多线程中sleep、yield、join的用法及sleep与wait区别?

 

如上面所示,将join改造成同步代码块如下所示,如果这段同步代码在start方法之前

看下结果,没有等待指定线程结束,main主线程就结束了

你能说出多线程中sleep、yield、join的用法及sleep与wait区别?

 

因为如果还没有调用start方法,那么isAlive是false(已开始未结束),主线程根本就不会等待,所以继续执行,然后继续到下面的start,然后主线程结束

所以,为什么join方法一定要在start之前?

就是因为这个isAlive方法的校验,你没有start,isAlive就是false,就不会同步等待,所以必须要先start,然后才能join

小结:

对于join方法,有两个关键:

  • 调用的哪个对象的join?
  • 在哪里调用的?

换一个说法:
join的效果是:一个线程等待另一个线程(直到结束或者持续一段时间)才执行,那么谁等待谁?

在哪个线程调用,哪个线程就会等待;调用的哪个Thread对象,就会等待哪个线程结束;

状态图回顾

在回顾下之前状态一文中的切换图,又了解了这几个方法后,应该对状态切换有了更全面的认识

你能说出多线程中sleep、yield、join的用法及sleep与wait区别?

 

总结

对于yield方法,比较容易理解,只是简单地对于CPU时间片的“礼让”,除非循环yield,否则一次yield,可能下次该线程仍旧可能会抢占到CPU时间片,可能方法调用和不调用没差别

sleep是静态方法,针对当前线程,进入休眠状态,两个版本的sleep方法始终有时间参数,所以必然会在指定的时间内苏醒,他也不会释放锁,当然,sleep方法的调用非必须在同步方法(同步代码块)内

join是实例方法,表示等待谁,是用于线程顺序的调度方法,可以做到一个线程等待另外一个线程,join有三个版本,指定超时时间或者持续等待直到目标线程执行结束,join也无需在同步方法(同步代码块)内

sleep和join都是可中断方法,被其他线程中断时,都会抛出InterruptedException异常,并且会醒来

 

join方法底层依赖wait,我们对比下wait与sleep

  • wait和sleep都会使线程进入阻塞状态,都是可中断方法,被中断后都会抛出异常
  • wait是Object的方法,sleep是Thread的方法
  • wait必须在同步中执行,sleep不需要(join底层依赖wait,但是不需要在同步中,因为join方法就是synchronized的)
  • wait会释放锁,sleep不会释放锁
  • wait(无超时设置的版本)会持续阻塞,必须等待唤醒,而sleep必然有超时,所以一定会自己醒来
  • wait 实例方法(Object),在对象上调用,表示在其上等待;sleep静态方法,当前线程
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

多线程中sleep、yield、join的用法及sleep与wait区别 的相关文章

  • c++11并发与多线程-王健伟-专题视频课程

    c 11并发与多线程 364人已学习 课程介绍 本课程 讲解的重点定位在c 11新标准中的多线程开发部分 同时 老师还会结合自己的经验把多线程的讲解进一步拓展到一个比较大的范畴 因为无论是c 11多线程开发还是各种其他的多线程开发实现方法
  • 云计算与Kubernetes(k8s)

    参考链接 https blog csdn net zkkzpp258 article details 86541362 https blog csdn net Bubbler 726 article details 85596418 htt
  • 谈谈form-data请求格式

    最近一直都比较忙 坚持月月更新博客的计划不得中止了 今天好不容易抽出点时间来说说最近项目中遇到的一个问题 有关request post请求格式中的multipart form data格式 引言 最近在项目过程中遇到一个问题 相信大部分人都
  • JUC AQS ReentrantLock源码分析(一)

    Java的内置锁一直都是备受争议的 在JDK 1 6之前 synchronized这个重量级锁其性能一直都是较为低下 虽然在1 6后 进行大量的锁优化策略 但是与Lock相比synchronized还是存在一些缺陷的 虽然synchroni
  • 对于进程同步和异步的理解

    多进程并发执行具有异步的特性 进程异步就是指一个以上的进程在并发执行时具有的异步特型 就比如说两个进程之间指令的执行顺序是不确定的 具有很强的随机性 举个例子 现在有两个并发执行的进程 A 和 B 各自都有n条指令需要执行 然而 我的CPU
  • Unsafe初探

    Unsafe Unsafe 是sun misc Unsafe下的一个包 通过这个类可以直接使用底层native方法来获取和操作底层的数据 例如获取一个字段在内存中的偏移量 利用偏移量直接获取或修改一个字段的数据等等 当然这个类正如他的名字一
  • 无锁和偏向锁有什么区别?

    无锁和偏向锁是 Java 中的两种轻量级锁实现 它们和重量级锁相比 具有更高的性能和更低的开销 它们之间的区别如下 无锁 CAS 自旋锁 无锁是一种不需要使用锁的同步技术 它的实现依赖于 CAS Compare And Swap 操作 通过
  • Python并发编程之线程池/进程池

    转载 http python jobbole com 87272 引言 Python标准库为我们提供了threading和multiprocessing模块编写相应的多线程 多进程代码 但是当项目达到一定的规模 频繁创建 销毁进程或者线程是
  • 多线程结合sprongboot事务(完善)

    避坑指南 1 Async Transactional不能在同一个方法上注解使用 原因Spring实现AOP的方法则就是利用了动态代理机制 正因如此 才会导致某些情况下 Async和 Transactional不生效 比如下面的将事务事务控制
  • 处理高并发、高访问之Apache优化

    前言 项目100人同时访问 导致访问速度变慢 作为一个没有遇到过这种情况下的辕 在各种查阅资料后 先用删除日志更改日志输出的方法处理后 处理方法 修改Apache日志输出相关配置方法 暂时好缓 后来又出现变慢 在查阅各种博客后 发现一个处理
  • 匿名内部类创建线程的两种方式

    我们知道多线程的实现有两种方式 一种是继承Thread类 另一种是实现Runnable接口 然后再重写run方法 最后开启线程 我们在普通的创建线程中 显然是比较麻烦的 那么有没有一个简单的方法呢 今天给大家介绍使用匿名内部类创建线程 为什
  • SSM实战项目——Java高并发秒杀API

    SSM实战项目 Java高并发秒杀API 项目截图 秒杀列表 秒杀详情页 错误提示 开始秒杀 秒杀成功 重复秒杀 秒杀倒计时 秒杀结束 项目介绍 何为秒杀 所谓 秒杀 就是网络卖家发布一些超低价格的商品 所有买家在同一时间网上抢购的一种销售
  • 【并发编程】CPU cache结构和缓存一致性(MESI协议)

    一 cache cpu cache已经发展到了三级缓存结构 基本上现在买的个人电脑都是L3结构 1 cache的意义 为什么需要CPU cache 因为CPU的频率太快了 快到主存跟不上 这样在处理器时钟周期内 CPU常常需要等待主存 浪费
  • 如何为Kafka集群选择合适的Topic/Partitions数量

    这是许多kafka使用者经常会问到的一个问题 本文的目的是介绍与本问题相关的一些重要决策因素 并提供一些简单的计算公式 越多的分区可以提供更高的吞吐量 首先我们需要明白以下事实 在kafka中 单个patition是kafka并行操作的最小
  • Semaphore 源码分析

    需要提前了解的知识点 AbstractQueuedSynchronizer 实现原理 类介绍 Semaphore 信号量 是用来控制同时访问特定资源的线程数量 它通过协调各个线程 以保证合理的使用公共资源 比如控制用户的访问量 同一时刻只允
  • 从操作系统层面理解同步、异步、阻塞、非阻塞

    同步和异步描述调用者会不会主动等待函数的返回值 举个例子 public void method int result otherMethod 像上面这种形式就叫同步 result 会一直等待 otherMethod 方法执行完毕并拿到返回值
  • 并发编程相关面试题(持续更新)

    1 juc包提供了哪些工具 用在什么场景 1 提供了比 synchronized 更加高级的各种同步结构 包括 CountDownLatch CyclicBarrier Semaphore 等 场景 可以实现更加丰富的多线程操作 比如利用
  • 并发问题(二)什么是并发

    1 什么是并发操作 并发操作是指同一时间可能有多个用户对同一数据进行读写操作 2 并发操作对数据的影响 如果对并发操作不做任何控制的话 会造成数据的不完整性 可能造成读脏数据 不可重复读 丢失修改还有幻读 3 对数据不完整性的举例 1 丢失
  • MySQL最常用的二种存储引擎MyISAM和InnoDB的介绍

    1 MyISAM 默认表类型 它是基于传统的ISAM类型 ISAM是Indexed Sequential Access Method 有索引的顺序访问方法 的缩写 它是存储记录和文件的标准方法 不是事务安全的 而且不支持外键 如果执行大量的
  • 并发编程----4.java并发包中线程池的原理研究

    并发编程 4 java并发包中线程池的原理研究 java并发包中线程池ThreadPoolExecutor的原理研究 线程池的优点 线程的复用 减少线程创建和销毁带来的消耗 提供了一种资源限制和线程管理的手段 比如限制线程的个数和动态新增线

随机推荐

  • Java之语言概述

    文章目录 1 软件开发介绍 1 1 常用的DOS命令 2 计算机编程语言介绍 3 Java语言概述 3 1 Java简史 3 2 Java技术体系平台 4 Java程序运行机制及运行过程 4 1 Java两种核心机制 2 垃圾收集机制 Ga
  • linux系统编程-2、进程

    前言 Linux系统编程的基础系列文章 随着不断学习会将一些知识点进行更新 前期主要是简单了解和学习 文章目录 进程 进程运行状态 进程原语 fork 进程相关函数 exec族 execl exec族区别 wait waitpid 进程 进
  • HTML中li去除样式以及占位问题

    在HTML中 使用 ul li li ul 的时候 总是会在列表的前面出现小圆点 去掉小圆点使用的方法很简单 就是直接使用CSS选择器进行选择之后进行样式的设定 具体应用如下 但是在去除小圆点之后仍然会存在问题 我们会发现使用此法去除小圆点
  • rest server的CRUD在线测试网站

    1 在sparkle的httpclientdemo中发现一个在线的测试网站 http httpbin org get 2 使用rest Debugger工具测试
  • 【前端】Vue项目:旅游App-(7)city:搜索框search和标签页Tabs

    文章目录 目标 过程与代码 搜索框 初步 自己实现取消功能 样式修改 标签页 效果 总代码 修改的文件 common css city vue main js 目标 过程与代码 搜索框 初步 在Vant文档中找到搜索框 Search搜索 按
  • SSH框架学习总结

    SSH框架学习总结 最终版权 JDram314 如转载请贴出出处 本来对SSH框架的学习可以早在去年 但是一直在给老师弄他的科研部分 所以一直拖到最近才算是学完了 乘现在有空总结一下 方便以后复习 一 Struts 在没有学习SSH框架前
  • MTK深圳公司嵌入式软件工程师笔试题(答案详解)

    1 1 define pi 3 142 define Area R pi R R3 main 4 5 int r1 5 r2 2 6 double s 0 7 s Area r1 r2 8 printf The area is f s 9
  • numpy.random.RandomState() numpy里random总结

    numpy random RandomState 函数用法 可以通过numpy工具包生成模拟数据集 使用RandomState获得随机数生成器 from numpy random import RandomState rdm RandomS
  • nginx+fastcgi+c/c++源码安装配置

    参考 http www cnblogs com xiaouisme archive 2012 08 01 2618398 html 由于以前安装过apache 已经安装了很多依赖库 现在只需要安装以下软件包 nginx 1 4 4 tar
  • s3cmd put 时提示 ERROR: S3 error: 403 (QuotaExceeded)

    配置里的rgw配额是10000000写满 s3cmd put 时提示 ERROR S3 error 403 QuotaExceeded rgw bucket default quota max objects 值为 1 查看配额信息 rad
  • 线性模型的介绍

    一 背景 在一个理想的连续世界中 任何非线性的东西都可以被线性的东西来拟合 所以理论上线性模型可以模拟物理世界中的绝大多数现象 线性模型 Linear Model 是机器学习中应用最广泛的模型 指通过样本特征的线性组合来进行预测的模型 给定
  • 【python基础知识】12.类与对象(一)

    类与对象 一 类 的基本概念 万事万物 皆为对象 类的创建和调用 我们都是中国人 类的创建 类的调用 总结 这篇文章中 我们会接触到一种全新的编程思维 面向对象编程 Object Oriented Programming 相信这种编程思维
  • Java基础(七): instanceof用法详解

    1 instanceof说明 instanceof 是 Java 的保留关键字 作用是 测试它左边的对象是否是它右边的类的实例 返回 boolean 的数据类型 instanceof是Java中的二元运算符 左边是对象 右边是类 当对象是右
  • MySQL中的各种查询

    文章目录 MySQL中的各种查询 基础查询 条件查询 排序查询 常见函数查询 分组查询 连接查询 内连接 外连接 交叉连接 子查询 联合查询 MySQL中的各种查询 基础查询 条件查询 语法 select 查询列表 from 表名 wher
  • html 与 js

    一 1 js java script js 基于对象 解释执行 java 面向对象 编译执行 2 html 引入 js 方式 1 内部 js body的最后一行 如下 3 控制台的输入输出 1 console log 内容 4 js 变量和
  • -lz -lrt -lm -lc都是什么库

    libz librt libm libc 压缩库 Z 实时库 real time 数学库 math 标准C库 C lib
  • get it [springmvc controller 单例说明以及多例切换]

    spring的bean作用域种类 1 singleton 单例模式 当spring创建applicationContext容器的时候 spring会欲初始化所有的该作用域实例 加上lazy init就可以避免预处理 2 prototype
  • Junit单元测试

    概念 JUnit是一个 Java 编程语言的单元测试工具 可以对部分代码的进行测试 Junit是用于Java的单元测试的框架 是别人写好的 特点 JUnit是一个开放源代码的测试工具 提供注解来识别测试方法 JUnit测试可以让你编写代码更
  • npm安装vue-cli,一直停留在deprecated request@2.88.2: request has been deprecated, see https://github.com/req

    安装vue cli出现的错误 原因 资源问题 没有配置淘宝镜像 解决 配置淘宝镜像 npm config set registry https registry npm taobao org 重新安装vue cli 即可成功 npm ins
  • 多线程中sleep、yield、join的用法及sleep与wait区别

    Object中的wait notify notifyAll 可以用于线程间的通信 核心原理为借助于监视器的入口集与等待集逻辑 通过这三个方法完成线程在指定锁 监视器 上的等待与唤醒 这三个方法是以锁 监视器 为中心的通信方法 除了它们之外