full outer join 与full join的区别_sleep、yield、join都是干啥的? sleep与wait有啥区别?中篇[十五]...
点击上方 “ 布衣码农 ” ,免费订阅~选择“ 设为星标 ”,第一时间免费获得更新~
「布衣码农」用不到却又不得不学习了解的底层方法+1。Object中的wait、notify、notifyAll,可以用于线程间的通信,核心原理为借助于监视器的入口集与等待集逻辑。通过这三个方法完成线程在指定锁(监视器)上的等待与唤醒,这三个方法是以锁(监视器)为中心的通信方法 。除了他们之外,还有用于线程调度、控制的方法,他们是sleep、yield、join方法,他们也可以用于线程的协作,他们是围绕着线程的调度而来的 。
sleep方法
有两个版本的sleep方法,看得出来,核心仍旧是native方法。非native方法只是进行了参数校验,接着仍旧是调用的native方法,这个情形与wait是类似的接下来仔细看下,native版本的sleep在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。该线程不丢失任何监视器的所属权。注意:sleep不会释放锁,不会释放锁,不会释放锁!!!可以理解为他进入监视器这个房间之后,在这房间里面睡着了。与wait类似的是,sleep也是可中断方法(从方法签名可以看得出来,可能抛出InterruptedException),也就是说如果一个线程正在sleep,如果另外的线程将他中断(调用interrupt方法),将会抛出异常,并且中断状态将会擦除。所以对于sleep方法,要么自己醒来,要么被中断后也会醒来。对于sleep始终有一个超时时间的设置,所以,尽管他是在监视器内睡着了,但是并不会导致死锁,因为他终究是要醒来的。如下,线程休眠500毫秒,主线程50毫秒打印一次状态ps:sleep方法的调用结果为状态:TIMED_WAITING借助于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(); }}
另外,你应该已经注意到sleep方法都有static修饰,既然是静态方法,在Thread中的惯例就是针对于:当前线程,当前线程,当前线程!
yield方法
对于sleep或者wait方法,他们都将进入特定的状态,伴随着状态的切换,也就意味着等待某些条件的发生,才能够继续,比如条件满足,或者到时间等。但是yield方法不涉及这些事情,他针对的是时间片的划分与调度,所以对开发者来说只是临时让一下,让一下他又不会死,就只是再等等yield方法将会暂停当前正在执行的线程对象,并执行其他线程,他始终都是RUNNABLE状态不过要注意,可以认为yield只是一种建议性的,如果调用了yield方法,对CPU时间片的分配进行了“礼让”,他仍旧有可能继续获得时间片,并且继续执行。所以一次调用yield 并不一定会代表肯定会发生什么。借助于while循环以及yield方法,也能一定程度上达到线程排序等待的效果yield也是静态方法,所以,也是针对于当前线程,当前线程,当前线程。
join方法
三个版本的join方法方法的实现过程,与wait也是非常类似,下面两个版本的方法一个调用join(0),一个参数校验后,调用join(millis),所以根本还是单参数版本的join方法在方法深入介绍前先看个例子一个线程,循环5次,每次sleep 1s,主线程中打印信息从结果可以看到,主线程总是在线程执行之后,才会执行。也就是主线程在等待我们创建的这个线程结束,结束了之后才会继续进行如果调整下顺序--->start 与 join的先后顺序,再次看下情况,可以发现顺序没有保障了结论:主线程main中调用启动线程(调用start),然后调用该线程的join方法,可以达到主线程等待工作线程运行结束才执行的效果,并且join要在start调用后如何做到的?从上面源代码可以看得出来,内部调用了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肯定等待线程结束)不过要注意:注释中有说明,自己不要使用Thread类的实例对象作为锁对象,如果是现在这种场景,使用join即可为什么?从目前来看,join方法就是以这个对象为锁,如果你自己在使用,又是wait又是notify(notifyAll)的,万一出现什么隐匿的问题咋办?所以join方法的原理就是:将指定的Thread实例对象作为锁对象,在其上进行同步,只要那个线程还活着,那么就会持续等待(或者有限时长)。线程终止之后会调用自身this.notifyAll,以通知在其上等待的线程。简单说,只要他活着大家就都等着, 他死了会通知,所以效果就是在哪里调用了谁的join,哪里就要等待这个线程结束,才能继续。为什么要在start之后?如上面所示,将join改造成同步代码块如下所示,如果这段同步代码在start方法之前看下结果,没有等待指定线程结束,main主线程就结束了因为如果还没有调用start方法,那么isAlive是false(已开始未结束),主线程根本就不会等待,所以继续执行,然后继续到下面的start,然后主线程结束。所以,为什么join方法一定要在start之前?就是因为这个isAlive方法的校验,你没有start,isAlive就是false,就不会同步等待,所以必须要先start,然后才能join小结:对于join方法,有两个关键:
调用的哪个对象的join?
在哪里调用的?
换一个说法:join的效果是:一个线程等待另一个线程(直到结束或者持续一段时间)才执行,那么谁等待谁?在哪个线程调用,哪个线程就会等待;调用的哪个Thread对象,就会等待哪个线程结束;
状态图回顾
在回顾下之前状态一文中的切换图,又了解了这几个方法后,应该对状态切换有了更全面的认识
总结
对于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静态方法,当前线程
··················END··················
注:非技术讲解配图均来源于网络
期待分享
如果对你有用
可以点个 「在看」 或者分享到 「 朋友圈 」 哦
你「在看」吗? ↓↓
full outer join 与full join的区别_sleep、yield、join都是干啥的? sleep与wait有啥区别?中篇[十五]...相关推荐
- oracle hash join outer,CSS_浅谈Oracle中的三种Join方法,基本概念
Nested loop join:
Outer - phpStudy...
浅谈Oracle中的三种Join方法 基本概念 Nested loop join: Outer table中的每一行与inner table中的相应记录join,类似一个嵌套的循环. Sort mer ...
- Java中sleep,wait,yield,join的区别
sleep() wait() yield() join()用法与区别 1.sleep()方法 在指定时间内让当前正在执行的线程暂停执行,但不会释放"锁标志".不推荐使用. slee ...
- 【Hive】left semi join(exists、in)和 left join 区别
left semi join(exists.in)和 left join 区别 left semi join 基本认识 对比 执行计划 小结 left semi join 基本认识 LEFT SEMI ...
- full join 和full outer join_多表关联:公式展开、join、过滤条件的顺序
这是在实现多表关联时想到的. 我们现在这套体系,实现多表关联比较复杂.如果Superset能官方支持多表关联,不知道会是什么样的方案,复杂度如何. 在公式这个层面,没有关联条件,只有两个列.或者多个列 ...
- mysql+join+合计_图解MySQL里的各种 JOIN,看完不懂来找我!
点击关注上方"SQL数据库开发", 设为"置顶或星标",第一时间送达干货作者:码志 链接:https://mazhuang.org/2017/09/11/joi ...
- 2021年大数据Flink(四十五):扩展阅读 双流Join
目录 扩展阅读 双流Join 介绍 Window Join Interval Join 代码演示1 代码演示2 重点注意 扩展阅读 双流Join 介绍 https:// ...
- Oracle的join默认为,Oracle中的三种Join方法详解
这里将为大家介绍Oracle中的三种Join方法,Nested loop join.Sort merge join和Hash join.整理出来以便帮助大家学习. 基本概念 Nested loop j ...
- 线程join_Java 并发编程:线程间的协作(wait/notify/sleep/yield/join)
点击上方"Coder编程",选择"置顶公众号" 技术文章第一时间送达! 并发编程.png 每天进步一点,不做curd工程师与Api调用工程师 欢迎访问 个人博客 ...
- left join 一对多_MYSQL 连接查询算法:JOIN语句在 MYSQL 内部到底是怎么执行的
前言 我们从一个问题引入今天的主题. 在日常业务开发中,我们可能经常听到 DBA 对我们说"不要"(注意:不是禁止)使用 join,那么为什么 DBA 对 join 这么抵触呢?是 ...
最新文章
- 高德拉特难题:悬赏5000美金的一道作业排序问题
- GCN代码超详解析Two-stream adaptive graph convolutional network for Skeleton-Based Action Recognition(三)
- html 数据库 编写学生表,用sql语句创建学生表如何做
- 【转】深入理解Windows消息机制
- 如何知道电脑服务器操作系统,电脑如何查看服务器操作系统
- iOS JSPatch 热修复使用
- [WM C++]从资源文件中加载显示png/jpg图片
- 整天说Code Review重要,你知道应该关注哪些关键点吗?
- 深入浅出 Javascript API(一)--基本框架
- h5 右下角浮动按钮_Flutter 浮动按钮-FloatingActionButton的使用
- 基于java 网页的宠物店管理系统
- VM虚拟机的安装及安装操作系统
- python基础(八):封装、继承、多态
- 洛谷 P3435 [POI2006]OKR-Periods of Words(KMP+记忆化搜索)
- 2020牛客暑期多校训练营(第九场)K-The Flee Plan of Groundhog
- 力扣OJ 剑指 Offer(1-30)
- IT开发团队分工及内容
- 计算机管理器用户怎么打开文件,资源管理器怎么设置默认打开我的电脑
- CVPR、ECCV 2020 两大会议论文分类索引
- 网卡不叫eth0,而叫ens33、ens160、eno1 or enp0s*?
热门文章
- selenium启动 IE11方法
- [Go语言]从Docker源码学习Go——init()方法和identifier首字母大小写区分
- 心得14--jsp遍历所有数据标签与转义标签
- hwnd = 0 各种粗心大意啊!
- GWT(Google Web Tookit) Eclipse Plugin的zip下载地址(同时提供GWT Designer下载地址)
- 《动手学深度学习》 第二天 (自动求梯度)
- php伪静态失败,php伪静态后html不能访问怎么办
- xshell 上下左右键乱码和退格键失效
- html文本改,编辑html格式文本可改成txt格式(可以替换或更换某文本)新手
- 青岛农商银行计算机防病毒应用培训,青岛农商银行胶州支行多元化培训提升安防管理水平...