一张图搞清楚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 ...
随机推荐
- 【链表】【python】力扣24. 两两交换链表中的节点【超详细的注释和解释】
目录 说在前面的话 前言 一.题目(力扣24. 两两交换链表中的节点) 二.题目分析 实现完整代码(Python实现) 总结 说在前面的话 博主也好长一段时间没有更新力扣的刷题系列了,今天给大家带来一 ...
- Python初学(请大神多多指教)
python的注释单行注释用#号多行注释用''' '''注释 基本数据类型 字符串-- n1 = "alex" n2 = 'root' n3 = " ...
- .NET Core开发实战(第2课:内容综述)--学习笔记
02 | 内容综述 课程目标 掌握 .NET Core 微服务架构的最佳实践 成长为一个具备良好架构设计能力的架构师 课程内容 第一部分 .NET Core 的必备知识 第二部分 .NET Core ...
- Visual Studio部署matplotlib绘图库的C++版本
本文介绍在Visual Studio软件中配置.编译C++环境下matplotlibcpp库的详细方法. matplotlibcpp库是一个C++环境下的绘图工具,其通过调用Python接口, ...
- NC20325 [SDOI2009]HH的项链
题目链接 题目 题目描述 HH有一串由各种漂亮的贝壳组成的项链. HH相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一 段贝壳,思考它们所表达的含义. HH不断地收集新的贝壳,因此他的项链 ...
- NC20875 舔狗舔到最后一无所有
题目链接 题目 题目描述 作为队伍的核心,forever97很受另外两个队友的尊敬. Trote_w每天都要请forever97吃外卖,但很不幸的是宇宙中心forever97所在的学校周围只有3家fo ...
- vue3的宏到底是什么东西?
前言 从vue3开始vue引入了宏,比如defineProps.defineEmits等.我们每天写vue代码时都会使用到这些宏,但是你有没有思考过vue中的宏到底是什么?为什么这些宏不需要手动从vu ...
- 内核5.4以上, Realtek 8111网卡初始化失败
在Centos7中, 升级内核到5.4.x或5.11.x时, 都会出现realtek8111网卡无法启动的问题, 在dmesg中能看到这个错误 $ dmesg |grep -i r8169 ... r ...
- IPFS Gateway Selector IPFS下载网关选择工具
简介 用IPFS作文件分享可以覆盖很多场景, 现在IPFS网关也相当多了, 但是因为国内网络的状况, 不同网关在不同网络运营商的表现差别很大, 导致你提供的下载链接在对方那里可能速度很慢, 甚至无法访 ...
- python中矩阵合并、拼接、组合
1 numpy数组 1.1 append() import numpy as np a=np.array([[1,3],[5,7]]) b=np.array([[2,4],[6,8]]) c=np.a ...