left join 和join区别_sleep、yield、join方法简介与用法 sleep与wait区别 多线程中篇

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

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

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

sleep方法

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

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

cf8f483d403275d34e11abc4542d69ec.png

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

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

注意:

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

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

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

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

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

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

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

149231581c607194cded097d032bcb34.png

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

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

package test1;
import java.lang.Thread.State;
public class T16 {
public static void main(String[] args) {
//模拟执行任务的第一个阶段的执行
Thread stepOne = new Thread(() -> {
System.out.println(Thread.currentThread().getName()+" : 第一阶段任务开始执行");
try {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+" : 第一阶段任务执行结束");
} catch (InterruptedException e) {
}
}, "firstStage");
stepOne.start();
//模拟任务第二个阶段的执行
Thread stepTwo = new Thread(() -> {
while (!State.TERMINATED.equals(stepOne.getState())) {
try {
Thread.sleep(100);
System.out.println(Thread.currentThread().getName()+" : 我在等待第一阶段任务执行结束");
} catch (InterruptedException e) {
}
}
System.out.println(Thread.currentThread().getName()+" : 第二阶段任务执行结束");
}, "secondStage");
stepTwo.start();
}
}

1a77428b7b9fa506d25c5989b0cb1727.png

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

yield方法

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

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

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

77d2e8c2928d878798d37858868b9112.png

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

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

0c1c75f6300c2a67a40df03c7caad477.png

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

49559be06cce65164dee647320eb7aeb.png

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

join方法

三个版本的join方法

0d5a3aff00a5713f4c1bb2aa1eeaccf6.png

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

32eeb761937c8dad40d9743024f055a1.png

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

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

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

f0b842ed81ff9e80e46298792b7e7814.png

301dc7c59051aab433774aa3b76a58a4.png

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

ed3d0c06ddc2e046e4ba52b7691f1a08.png

结论:

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

如何做到的?

560711e8c9498f5e7b8031fa60b48fc1.png

从上面源代码可以看得出来,内部调用了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肯定等待线程结束)

b0ee55bfec61ad8607fabdbecc118db3.png

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

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

06cb201158fda352a336ed562c5ff569.png

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

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

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

为什么要在start之后?

966351c56f8ce1b29e3d1d8dfebee070.png

如上面所示,将join改造成同步代码块如下所示,如果这段同步代码在start方法之前
看下结果,没有等待指定线程结束,main主线程就结束了

97cedfa481f5c514b21905cfc46ca05f.png


因为如果还没有调用start方法,那么isAlive是false(已开始未结束),主线程根本就不会等待,所以继续执行,然后继续到下面的start,然后主线程结束
所以,为什么join方法一定要在start之前?就是因为这个isAlive方法的校验,你没有start,isAlive就是false,就不会同步等待,所以必须要先start,然后才能join
小结:
对于join方法,有两个关键:

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

换一个说法:join的效果是:一个线程等待另一个线程(直到结束或者持续一段时间)才执行,那么谁等待谁?在哪个线程调用,哪个线程就会等待;调用的哪个Thread对象,就会等待哪个线程结束;状态图回顾
在回顾下之前状态一文中的切换图,又了解了这几个方法后,应该对状态切换有了更全面的认识

f78423b848102a93fbd3f2e202a61e2a.png

总结

对于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静态方法,当前线程

来源:博客园

作者:noteless

原文:sleep、yield、join方法简介与用法 sleep与wait区别 多线程中篇

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

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

相关文章

深度干货!值得精读的2018自动驾驶行业发展报告

来源&#xff1a; 机器人大讲堂摘要随着科技革命的深入推进&#xff0c;人类社会进入万物互联、万物智能的智能化新时代。自动驾驶技术在人工智能和汽车行业的飞速发展下逐渐成为业界焦点。自动驾驶技术是汽车产业与高性能计算芯片、人工智能、物联网等新一代信息技术深度融合的…

TCP 连接状态

TCP十一种状态 全部11种状态 1. 客户端独有的&#xff1a;&#xff08;1&#xff09;SYN_SENT &#xff08;2&#xff09;FIN_WAIT1 &#xff08;3&#xff09;FIN_WAIT2 &#xff08;4&#xff09;CLOSING &#xff08;5&#xff09;TIME_WAIT 。 2. 服务器独有的&#xff1a…

Java加密与解密的艺术~MD算法实现

MD系列算法的实现是通过MessageDigest类来完成的&#xff0c;如果需要以流的处理方式完成消息摘要&#xff0c;则需要使用DigestInputStream和DigestOutputStream。 MD4 package org.zlex.chapter06_1_2;import java.security.MessageDigest; import java.security.Security;i…

密码学知识

文章目录密码学一、对称加密体系二、模式三、非对称加密体系四、数据完整性五、数字签名六、国密算法七、SSL协议八、CA密码学 提示&#xff1a;本文包括常见的对称加密和非对称加密算法&#xff0c;hash&#xff0c;数字签名 提示&#xff1a;以下是本篇文章正文内容&#xf…

德勒报告:2018年全球生命科学发展趋势

来源&#xff1a;新浪医药、战略前沿技术健康生命科学&#xff08;Health life sciences&#xff09;是指应用生物学和技术来促进健康护理&#xff0c;包括制药、医疗技术、基因组学、诊断学、数字医疗等等。这一板块产品种类繁多&#xff0c;包括药品、医疗技术、诊断和数字工…

Uber致人死亡或为自动驾驶肇事责任 没有判例可循

图&#xff1a;Uber自动驾驶测试车辆引发致人死亡交通事故凤凰网科技讯 据《福布斯》网站北京时间3月20日报道&#xff0c;美国当地时间本周日傍晚&#xff0c;一辆由Uber运营的自动驾驶汽车在亚利桑那州坦佩(Tempe)撞倒了一名女性并致其死亡。Uber周一表示&#xff0c;公司暂停…

28个Unix/Linux的命令行神器

From: http://os.51cto.com/art/201207/347414.htm 下面收集的Unix/Linux下的28个命令行下的工具&#xff0c;有一些是大家熟悉的&#xff0c;有一些是非常有用的&#xff0c;有一些是不为人知的。这些工具都非常不错&#xff0c;希望每个人都知道。本篇文章还在Hacker News上被…

Java加密与解密的艺术~SHA算法实现

MesssageDigest类也支持SHA算法&#xff0c;主要包含SHA-1、SHA-256、SHA-384和SHA-512四种算法。通过第三方加密组件包Bouncy Castle&#xff0c;可支持SHA-224算法。 SHA Java原始 /*** 2009-9-3*/ package org.zlex.chapter06_2_1;import java.security.MessageDigest; /**…

linux 无法打开.ttf_win7系统ttf文件打不开怎么办【解决方法】

我们都清楚ttf文件是windows系统当中的字体文件&#xff0c;能够直接通过这个文件进行字体的添加&#xff0c;不过最近有位win7系统用户却遇到了ttf文件无法打开的情况&#xff0c;系统提示“该文件没有与之关联的程序来执行该操作。请安装一个程序&#xff0c;或者&#xff0c…

全球20大智慧城市排行榜揭晓:无锡列中国第一,银川、杭州上榜!

来源&#xff1a;Juniper Research、物联网智库近日&#xff0c;英国市场调研机构Juniper Research发布了“全球智慧城市Top 20”的榜单&#xff0c;这份榜单从出行、医疗、公共安全和工作效率四个方面对城市的智能化程度进行综合评定&#xff0c;并揭示了这些城市在节省时间、…

Mono 2.0

Mono 2.0 Mono 2.0 发布有一段时间了,早就想体验一下,一直没时间,最近比效闲,非常闲,于是就尝试了一下Mono 2.0 操作系统 考虑到兼容问题,我没选择常用的Rad Hat,而是选择了openSUSE 11.0 , openSUSE 11.0 我也是第一次用, 在Virtual PC 2007上安装,每次到开始安装就黑屏,…

Java加密与解密的艺术~MAC算法实现

Java 原生 /*** 2009-9-10*/ package org.zlex.chapter06_3_1;import javax.crypto.KeyGenerator; import javax.crypto.Mac; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec;/*** MAC加密组件* * author 梁栋* version 1.0* since 1.0*/ public abs…

mysql rpm 启动_MySQL安装(rpm)和启动配置

MySQL安装(rpm)和启动配置安装环境&#xff1a;OS&#xff1a;Oracle Linux 5.9安装步骤&#xff1a;1.解压MySql安装包[rootbakdbserver mysql]# tar -xf MySQL-5.5.24-1.rhel5.x86_64.tar[rootbakdbserver mysql]# ll总计 373920-rw-r--r-- 1 root root 191242240 2012-05-2…

量子计算陷入难解困境,未来发展何去何从?

来源&#xff1a;科研圈量子计算机在一些具体任务上的表现很快就能超越传统电子计算机&#xff0c;但是在量子计算真正实现其巨大潜力前&#xff0c;依然需要克服许多基础性的难题。在量子计算的可行性被质疑长达几十年后&#xff0c;全世界范围内忽然掀起了对于量子计算的追逐…

mysql 64位 8.0.11_mysql8.0.11 在windows64安装 步骤

环境&#xff1a;Windows 101一、安装1. 解压zip包到安装目录比如我的安装目录是&#xff1a;D:\Program\MySQL2.配置文件在Windows系统中&#xff0c;配置文件默认是安装目录下的 my.ini 文件&#xff0c;部分配置需要在初始安装时配置&#xff0c;大部分也可以在安装完成后进…

ProxyChains

proxychains-ng&#xff1a;https://github.com/rofl0r/proxychains-ng proxychains&#xff1a;https://github.com/haad/proxychains shadowsocks&#xff1a;https://github.com/shadowsocks/shadowsocks 安装了 shadowsocks 之后&#xff0c;只能网页出去逛逛&#xff0c;…

IDC发布对话式人工智能白皮书|附下载

来源&#xff1a;专知丨公众号近日&#xff0c;全球著名的信息技术、电信行业和消费科技咨询公司IDC&#xff08;国际数据公司&#xff0c; International Data Corporation&#xff09;发布了《对话式人工智能白皮书》&#xff08;下文简称《白皮书》&#xff09;。《白皮书》…

Java加密与解密的艺术~思维导图

#原图 System.out.println("https://www.processon.com/view/link/61a8323fe401fd49ed41cde0");

一场关于Google不作恶信条的辩论会

2008年11月18日&#xff0c;Intelligence Squared 在纽约 Rockefeller 大学召开了一次关于 Google 不作恶信条&#xff08;Dontt be evil Motto&#xff09;的辩论会&#xff0c;这场牛津式辩论会&#xff08;Oxford-style debate &#xff09;持续了近两个小时&#xff0c;《纽…

2017美国人工智能和机器学习行业种子投资首次下降

来源&#xff1a;199IT互联网数据中心根据Crunchbase的数据&#xff0c;风险投资对机器学习和人工智能的热情已经开始趋于平静&#xff0c;至少在美国是这样。但这可能并不是一件坏事。尽管人工智能和机器学习成为学术研究的热点领域已经有数十年了&#xff0c;但是尚未成为风险…