文章目录
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