一张图搞清楚wait、sleep、join、yield四者区别,面试官直接被征服!
写在开头
在线程的生命周期中,不同状态之间切换时,可以通过调用sleep()、wait()、join()、yield()等方法进行线程状态控制,针对这一部分知识点,面试官们也会做做文章,比如问你这些方法的作用以及之间的区别。
那么今天我们就一起来总结一下这几个方法的作用及区别,先画一个思维导图梳理一下,便于理解与记忆,争取在被问到这个点时彻底征服面试官!(图片可保存常看哈)

sleep()
sleep()是Thread类中的一个静态本地方法,通过设置方法中的时间参数,使调用它的线程休眠指定时间,线程从RUNNING状态转为BLOCKED状态,这个过程中会释放CPU资源,给其他线程运行机会时不考虑线程的优先级,但如果有同步锁则sleep不会释放锁即其他线程无法获得同步锁,需要注意的是sleep()使用时要处理异常。休眠时间未到时,可通过调用interrupt()方法来唤醒休眠线程。
【代码示例1】
try {//sleep会发生异常要显示处理
Thread.sleep(20);//暂停20毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}
为什么sleep()放在Thread类中
答:因为sleep是线程级别的休眠,不涉及到对象类,只是让当前线程暂停,进入休眠状态,并不释放同步锁资源,也不需要去获得对象锁。
wait()
wait() 是Object类的成员本地方法,会让持有对象锁的线程释放锁,进入线程等待池中等待被再次唤醒(notify随机唤醒,notifyAll全部唤醒,线程结束自动唤醒)即放入锁池中竞争同步锁,同时释放CPU资源,它的调用必须在同步方法或同步代码块中执行,也需要捕获 InterruptedException 异常。
【代码示例2】
//同步代码块
synchronized (obj) {
System.out.println("obj to wait on RunnableImpl1");
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("obj continue to run on RunnableImpl1");
}
为什么wait()是Object的方法
答:每个对象都拥有对象锁,wait的作用是释放当前线程所占有的对象锁,自然是要操作对应的Object而不是Thread,因此wait要放入到Object中。
join()
join()同样是Thread中的一个方法,调用join的线程拥有优先使用CPU时间片的权利,其他线程需要等待join()调用线程执行结束后才能继续执行,探索其底层会发现,它的底层是通过wait()进行实现,因此它也需要处理异常。
【代码示例3】
//创建TestRunnable类
TestRunnable mr = new TestRunnable();
//创建Thread类的有参构造,并设置线程名
Thread t1 = new Thread(mr, "t1");
Thread t2 = new Thread(mr, "t2");
Thread t3 = new Thread(mr, "t3");
//启动线程
t1.start();
try {
t1.join(); //等待t1执行完才会轮到t2,t3抢
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
t3.start();
我们跟进join()方法内部会发现,其底层主要通过wait()实现,其中参数代表等待当前线程最多执行 millis 毫秒,如果 millis 为 0,则会一直执行,直至完成,其他线程才会继续向下;
【源码示例1】
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
yield()
yield()是Thread的一个静态方法,它的调用不需要传入时间参数,并且yield() 方法只会给相同优先级或更高优先级的线程运行的机会,并且调用yield的线程状态会转为就绪状态,调用yield方法只是一个建议,告诉线程调度器我的工作已经做的差不多了,可以让别的线程使用CPU了,没有任何机制保证采纳。所以可能它刚让出CPU时间片,又被线程调度器分配了一个时间片继续执行了。使用时不需要处理异常。
【代码示例4】
public class Test {
public static void main(String[] args) {
Thread thread1 = new Thread(Test::printNumbers, "小明");
Thread thread2 = new Thread(Test::printNumbers, "小华");
thread1.start();
thread2.start();
}
private static void printNumbers() {
for (int i = 1; i <= 5; i++) {
System.out.println(Thread.currentThread().getName() + ": " + i);
// 当 i 是偶数时,当前线程暂停执行
if (i % 2 == 0) {
System.out.println(Thread.currentThread().getName() + " 让出控制权...");
Thread.yield();
}
}
}
}
输出:
小明: 1
小华: 1
小华: 2
小明: 2
小明 让出控制权...
小华 让出控制权...
小明: 3
小明: 4
小明 让出控制权...
小明: 5
小华: 3
小华: 4
小华 让出控制权...
小华: 5
总结
上文中,我们结合代码示例,对这个四个方法进行了详细介绍,下面我们以sleep()为参照,进行对比总结:
(1)sleep()与wait()的区别?
- sleep() 是 Thread 类的静态本地方法;wait() 是Object类的成员本地方法;
- JDK1.8 sleep() wait() 均需要捕获 InterruptedException 异常;
- sleep() 方法可以在任何地方使用;wait() 方法则只能在同步方法或同步代码块中使用;
- sleep() 会休眠当前线程指定时间,释放 CPU 资源,不释放对象锁,休眠时间到自动苏醒继续执行;wait() 方法放弃持有的对象锁,进入等待队列,当该对象被调用 notify() / notifyAll() 方法后才有机会竞争获取对象锁,进入运行状态。
(2)sleep()与yield()的区别?
- sleep() 方法给其他线程运行机会时不考虑线程的优先级;yield() 方法只会给相同优先级或更高优先级的线程运行的机会;
- sleep() 方法声明抛出 InterruptedException;yield() 方法没有声明抛出异常;
- 线程执行 sleep() 方法后进入超时等待状态;线程执行 yield() 方法转入就绪状态,可能马上又得得到执行;
- sleep() 方法需要指定时间参数;yield() 方法出让 CPU 的执行权时间由 JVM 控制。
(3)sleep()与join()的区别?
- JDK1.8 sleep() join() 均需要捕获 InterruptedException 异常;
- sleep()是Thread的静态本地方法,join()是Thread的普通方法;
- sleep()不会释放锁资源,join()底层是wait方法,会释放锁。
结尾彩蛋
如果本篇博客对您有一定的帮助,大家记得留言+点赞+收藏呀。原创不易,转载请联系Build哥!

如果您想与Build哥的关系更近一步,还可以关注“JavaBuild888”,在这里除了看到《Java成长计划》系列博文,还有提升工作效率的小笔记、读书心得、大厂面经、人生感悟等等,欢迎您的加入!

一张图搞清楚wait、sleep、join、yield四者区别,面试官直接被征服!的更多相关文章
- 一张图搞懂Spring bean的完整生命周期
一张图搞懂Spring bean的生命周期,从Spring容器启动到容器销毁bean的全过程,包括下面一系列的流程,了解这些流程对我们想在其中任何一个环节怎么操作bean的生成及修饰是非常有帮助的. ...
- 一张图搞定OAuth2.0 在Office应用中打开WPF窗体并且让子窗体显示在Office应用上 彻底关闭Excle进程的几个方法 (七)Net Core项目使用Controller之二
一张图搞定OAuth2.0 目录 1.引言 2.OAuth2.0是什么 3.OAuth2.0怎么写 回到顶部 1.引言 本篇文章是介绍OAuth2.0中最经典最常用的一种授权模式:授权码模式 非常 ...
- 两张图搞清楚Eclipse上的Web项目目录
从MyEclipse转到Eclipse起初有点不习惯eclipse的目录结构,顺手一查看到的文章帮助很大,转载一下: 原文链接:https://www.jianshu.com/p/91050dfcbe ...
- 一张图搞清楚PMBOK所有过程的使用
很多参加PMP培训的学员大概都会有一个感受,上课时似乎每个知识点都听懂了,大的知识框架也弄明白了,但是所有这些串起来在实践中怎么用呀!说的再直接一点,在考试的时候这些过程和活动是以怎样的逻辑来应用 ...
- 一张图搞懂容器所有操作 - 每天5分钟玩转 Docker 容器技术(26)
前面我们已经讨论了容器的各种操作,对容器的生命周期有了大致的理解,下面这张状态机很好地总结了容器各种状态之间是如何转换的. 如果掌握了前面的知识,要看懂这张图应该不难.不过有两点还是需要补充一下: 可 ...
- 一张图搞定OAuth2.0
1.引言 本篇文章是介绍OAuth2.0中最经典最常用的一种授权模式:授权码模式 非常简单的一件事情,网上一堆神乎其神的讲解,让我不得不写一篇文章来终结它们. 一项新的技术,无非就是了解它是什么,为什 ...
- 一张图搞定 .NET Framework, .NET Core 和 .NET Standard 的区别
最近开始研究.NET Core,有张图一看就能明白他们之前的关系. 上图己经能够说明.NET Framework和.NET Core其实是实现了 .NET Standard相关的东西,或者说Frame ...
- 一张图搞懂Ajax原理
本文整理在,我的github上.欢迎Star. 原理 说起ajax,就不得不说他背后的核心对象XMLHttpRequest,而说到XMLHttpRequest我觉得,从它的readyState状态说起 ...
- 一句话+两张图搞定JDK1.7HashMap,剩下凑字数
JDK1.7 HashMap一探究竟 HashMap很简单,原理一看散列表,实际数组+链表;Hash找索引.索引若为null,while下一个.Hash对对碰,链表依次查.加载因子.75,剩下无脑扩数 ...
- 硬核!八张图搞懂 Flink 端到端精准一次处理语义 Exactly-once(深入原理,建议收藏)
Flink 在 Flink 中需要端到端精准一次处理的位置有三个: Source 端:数据从上一阶段进入到 Flink 时,需要保证消息精准一次消费. Flink 内部端:这个我们已经了解,利用 Ch ...
随机推荐
- Load-balanced-online-OJ-system 负载均衡的OJ系统项目
前言 那么这里博主先安利一些干货满满的专栏了! 首先是博主的高质量博客的汇总,这个专栏里面的博客,都是博主最最用心写的一部分,干货满满,希望对大家有帮助. 高质量博客汇总 本项目Github地址 - ...
- Exadata健康检查工具EXAchk
本文根据MOS文章:Oracle Exadata Database Machine EXAchk (Doc ID 1070954.1)整理关键步骤. 注:通常都会要求使用当前最新可用的EXAchk版本 ...
- dbgrideh 下拉显示多列
- Hive报错:Call From hadoop01/172.23.238.2 to hadoop01:10020 failed on connection exception
问题描述 在阿里云服务器上安装的Hadoop和Hive,刚开始关闭了防火墙.但是由于服务器被被黑客安装挖矿程序,所以开启了防火墙.但是即使开启了所有可能的端口,但是在向Hive中插入数据时,依然报错提 ...
- 多线程系列(二) -Thread类使用详解
一.简介 在之前的文章中,我们简单的介绍了线程诞生的意义和基本概念,采用多线程的编程方式,能充分利用 CPU 资源,显著的提升程序的执行效率. 其中java.lang.Thread是 Java 实现多 ...
- ES6学习 第三章 字符串的扩展
前言 本章主要是内容为是 ES6 对字符串的改造和增强. 本章记录字符串的扩展常用重点部分,不常用知识稍作记录. 本章原文链接: 字符串的扩展 模板字符串(template string) ES6字符 ...
- NC23619 小A的柱状图
题目 题目描述 柱状图是有一些宽度相等的矩形下端对齐以后横向排列的图形,但是小A的柱状图却不是一个规范的柱状图,它的每个矩形下端的宽度可以是不相同的一些整数,分别为 \(a[i]\) ,每个矩形的高度 ...
- Linux 中iostat 命令详解
iostat命令详解 iostat 主要是统计 磁盘活动情况. iostat有以下缺陷: iostat的输出结果大多数是一段时间内的平均值,因此难以反映峰值情况iostat仅能对系统整体情况进行分析汇 ...
- Python 装饰器解析(二)
前面一篇文章介绍了python装饰器,最后引入了functools.wraps的使用,本篇文章将对它进行深入的探究. functools模块提供了一系列的高阶函数以及对可调用对象的操作,其中为人熟知的 ...
- Java核心技术卷1:基础知识(原书第10版)
本书为专业程序员解决实际问题而写,Java基础知识面覆盖很完整,可以帮助你深入了解Java语言和库.在卷I中,Horstmann主要强调基本语言概念和现代用户界面编程基础,深入介绍了从Java面向对象 ...