

一张图搞清楚wait、sleep、join、yield四者区别,面试官直接被征服! - JavaBuild
source link: https://www.cnblogs.com/JavaBuild/p/18074175
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

在线程的生命周期中,不同状态之间切换时,可以通过调用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成长计划》系列博文,还有提升工作效率的小笔记、读书心得、大厂面经、人生感悟等等,欢迎您的加入!
Recommend
-
47
产品小白专属,10周线上特训,测、练、实战,22位导师全程带班,11项求职服务,保障就业! 了解详情 释放双眼,带上耳机,听听看~! 00:00 00:00
-
20
Flink 在 Flink 中需要端到端精准一次处理的位置有三个: 图片 Flink 端到端精准一次处理 Source 端:数据从上一阶段进入到 Flink 时,需要保证消息精准一次消费。 Flink 内部端:这个我们已经了解,利用 Check...
-
8
三张图搞懂JavaScript的原型对象与原型链爱前端不爱恋爱关注微信公众号:web前端学习圈,领取85G前端全套系统教程
-
10
Arduino、arm、树莓派、单片机四者有什么不同?
-
4
在微服务架构或分布式环境下,服务注册与发现技术不可或缺,这也是程序员进阶之路必须要掌握的核心技术之一,本文通过图解的方式带领大家轻轻松松掌握。引入服务注册与发现组件的原因先来看一个问题,假如现在我们要做一个商城项目,作为架构师...
-
28
一文搞清楚URL和URI的区别到底是什么 – Android开发中文站 Android开发中文站 ...
-
6
LED和OLED电视有什么区别,这些差异要清楚,别买错了 2023-01-17 07:13:00 来源:
-
10
UI 设计和 UX 设计有什么区别?从4个方面给你说清楚! 更新时间:2023-02-10 10:39:37 UI 设计和 UX 设计有什么区别?我想最简单的划分就是,UI 重视视觉,UX 重视体验。但实际上两者都有交叉的地方,随着互联网技术的发展,...
-
5
面试官:“我们在Java的集合和数据结构中都离不开比较器,请你聊一聊Comparable 和 Comparator 这两种的区别吧” 内心活动:“上来就这么直接吗,那些ArrayList,HashMap都不问呀,好,既然如此,那让我来征服你吧,面试官大人!” 我:“好滴!巴拉巴拉~”
-
5
面试官:小伙子请聊一聊Java中的精灵线程? 我:什么?精灵线程?啥时候精灵线程? 面试官:精灵线程没听过?那守护线程呢? 我:守护线程知道,就是为普通线程服务的线程嘛。 面试官:没了?守护线程的特点,怎么使用,需要注意啥,Java中...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK