Java - sleep yield wait notify notifyAll join 方法功能解析

1 sleep 方法解析

  • 通过调用 Thread.sleep(…) 方法来操作当前线程,不能操作其它线程
  • 调用 sleep 方法后线程进入 Time_Waiting 状态(有限等待状态),且不会释放锁,让出 CPU 时间,当时间到了,进入可运行状态(RUNNABLE)
  • 调用sleep方法后,线程如果被中断,会抛出异常,并清除中断状态
  • 如果线程先被中断,后调用 sleep 方法,也会抛异常,并清除中断状态
  • 中断一个非活动线程没有任何效果(线程运行之前调用 interrupt() 方法没有任何意义)
  • 调用interrupt后线程为中断状态
//使当前执行的线程休眠(暂时停止执行)指定的毫秒数,取决于系统计时器和调度程序的精度和准确性。线程不会丢失任何监视器的所有权
//如果有线程中断了当前的线程(调用Thread.sleep(..)方法的线程),则会抛出 InterruptedException 异常,并且抛出此异常之后,当前线程的中断状态将被清除
public static native void sleep(long millis) throws InterruptedException;
//精确到纳秒级别
public static native void sleep(long millis, int nanos) throws InterruptedException;
//如果某个线程调用了 wait(..)、join(..)、sleep(..)方法被阻塞后调用了这个方法,会清除中断状态,并抛出异常(翻译)
//中断一个非活动线程没有任何效果
public void interrupt() {
   ...}

2 yield 方法解析

  • 和 sleep() 方法一样都是 Thread 类中的静态方法
  • 声明让出 CPU 时间,但可能继续执行,不释放锁
  • 一般不建议使用该方法
//向调度器声明可以让出 CPU 时间,调度器可以忽略该声明,继续让该线程执行
//Yield是一种启发式尝试,用于改善线程之间的相对进展,否则会过度利用CPU。 它的使用应与详细的分析和基准测试相结合,以确保它实际上具有所需的效果。
//这个方法很少使用。 它可能对调试或测试目的很有用,它可能有助于重现因竞争条件而产生的错误。 在设计并发控制结构(例如java.util.concurrent.locks包中的结构)时,它也可能很有用
public static native void yield();

3 wait 方法解析

  • 调用 wait() 无参方法后,线程为 WATING 状态(无限等待状态),调用由此方法进入 Time_WATING 状态(有限等待状态)
  • 当前线程必须拥有一个监视器(在 synchronized 块之内)对象
  • 使当前线程等待,直到另一个线程为此对象(当前线程拥有的监视器对象)调用notify() 方法或 notifyAll() 方法,或者已经过了一定的实时时间
  • 此方法使当前线程将自身置于监视器对象的等待队列中,并且释放该监视器对象的锁。出于线程调度目的,此线程将被禁用,并处于休眠状态,直到发生以下四种情况之一:
    • 别的线程调用了监视器对象的 notify() 方法后,会随机唤醒一个该监视器对象等待队列中的休眠线程
    • 别的线程调用了监视器对象的 notifyAll() 方法后,会唤醒该监视器对象等待队列中的所有休眠线程
    • 别的线程中断了该线程(注意调用 wait() 方法后线程已经没有锁啦,会直接进入异常流程)
    • 如果参数大于0,则大约过了这个参数的时间(毫秒),线程会自动苏醒。如果参数为0,必须等待前三个通知。小于0直接抛异常
  • 如果一个线程获得了多个监视器对象,调用一个监视器对象的 wait() 方法只会释放这一个监视器对象,不会释放其它
  • 当线程被唤醒后,会和其它线程一起公平竞争该监视器,一旦有个线程竞争成功,其它线程都会处于,线程调用 wait() 方法后的那个状态(等待队列中休眠)
  • 注意: 即使没有上述说的四种情况,线程也可能会唤醒(实际上虽然很少很少发生),所以建议 wait() 方法放在 while 修饰的条件下,而不是 if,防止异常唤醒!
  • 调用 wait() 方法后被中断会抛异常
public final native void wait(long timeout) throws InterruptedException;
//很奇怪, nanos 参数只要在 0< nanos< 999999 之内,该方法会直接调用 wait(++timeout),即都只是多了一个毫秒数
public final native void wait(long timeout, int nanos) throws InterruptedException;

4 notify() 方法解析

  • 当前线程必须拥有一个监视器(在 synchronized 块之内)对象

  • 唤醒正在等待此对象监视器的单个线程。如果有任何线程正在等待这个对象,那么将选择唤醒其中一个线程。选择是任意的

  • 被唤醒的线程必须等待当前线程放弃监视器(退出 synchronized 块)后,才能继续

public final native void notify();

5 notifyAll() 方法解析

  • 唤醒正在等待此对象监视器的所有线程
  • 其余和 notify() 方法一样

6 join() 方法解析

  • 关键: t.join(…) 方法已经被 synchronized 修饰了!所以当前线程调用某个线程对象的 join() 方法,说明当前对象获取了这个线程对象的监视器!
  • 可以看出 join() 方法内部主要是调用 wait() 方法,并且使用 while 包围了 wait() 方法,这样当不正确唤醒当前线程时,当条件不满足时,仍然会回归正轨!
  • 当 t.join() 方法参数为0时,调用这个方法的线程必须一直等到线程 t 死亡后,才能继续运行
  • 当 t.join() 方法参数大于0时,调用这个方法的线程等到线程 t 死亡 或 等待参数的毫秒时间后,会继续运行
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()) {
   //判断this对象线程是否存活,如果存活就一直等待!只有被唤醒了,并且this对象线程死了,才会退出 while!
            wait(0);// 当 this 线程死之前,会调用 notifyAll() 方法,唤醒所有等待线程,
            //所以,只有 this 线程死了,才会退出循环
        }
    } else 
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值