写点什么

一张图搞清楚 wait、sleep、join、yield 四者区别,面试官直接被征服!

  • 2024-03-15
    福建
  • 本文字数:2775 字

    阅读完需:约 9 分钟

写在开头


在线程的生命周期中,不同状态之间切换时,可以通过调用 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()的区别?

  1. sleep() 是 Thread 类的静态本地方法;wait() 是 Object 类的成员本地方法;

  2. JDK1.8 sleep() wait() 均需要捕获 InterruptedException 异常;

  3. sleep() 方法可以在任何地方使用;wait() 方法则只能在同步方法或同步代码块中使用;

  4. sleep() 会休眠当前线程指定时间,释放 CPU 资源,不释放对象锁,休眠时间到自动苏醒继续执行;wait() 方法放弃持有的对象锁,进入等待队列,当该对象被调用 notify() / notifyAll() 方法后才有机会竞争获取对象锁,进入运行状态。


(2)sleep()与 yield()的区别?

  1. sleep() 方法给其他线程运行机会时不考虑线程的优先级;yield() 方法只会给相同优先级或更高优先级的线程运行的机会;

  2. sleep() 方法声明抛出 InterruptedException;yield() 方法没有声明抛出异常;

  3. 线程执行 sleep() 方法后进入超时等待状态;线程执行 yield() 方法转入就绪状态,可能马上又得得到执行;

  4. sleep() 方法需要指定时间参数;yield() 方法出让 CPU 的执行权时间由 JVM 控制。


(3)sleep()与 join()的区别?

  1. JDK1.8 sleep() join() 均需要捕获 InterruptedException 异常;

  2. sleep()是 Thread 的静态本地方法,join()是 Thread 的普通方法;

  3. sleep()不会释放锁资源,join()底层是 wait 方法,会释放锁。


文章转载自:JavaBuild

原文链接:https://www.cnblogs.com/JavaBuild/p/18074175

体验地址:http://www.jnpfsoft.com/?from=001

用户头像

还未添加个人签名 2023-06-19 加入

还未添加个人简介

评论

发布
暂无评论
一张图搞清楚wait、sleep、join、yield四者区别,面试官直接被征服!_Java_不在线第一只蜗牛_InfoQ写作社区