💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] ## 1. sleep 1. wait,sleep,join,I/O导致的block,会被interrupted方法中断. 2. 这些可中断方法,在捕捉到中断信号后,也就是捕获了InterruptedException异常,就会擦出interrupt标识。 ![](https://img.kancloud.cn/5e/25/5e25031c64ea05891284fe4d5cf47d50_1018x262.png) 因为捕获到了信号,所以标识被擦出,输出false ## 1.1 特性 1、使线程进入执行时间的休眠 2、不会放弃monitor锁的所有权 ## 1.2 TimeUnit ### 1.2.1 省去换算,表达清晰 是一个枚举类,对sleep进行了很好的封装,并省去了时间换算的过程。例如使线程休眠4分15秒 1、以前的写法是 ~~~ Thread.sleep(4*60*1000 + 15 * 1000); ~~~ 2、TimeUnit省去换算 ,而且清晰 ~~~ TimeUnit.MINUTES.sleep(4); TimeUnit.SECONDS.sleep(15); ~~~ ### 1.2.2 时间不同单位之间的换算 TimeUnit还提供了便捷方法用于把时间转换成不同单位,例如,如果你想把秒转换成毫秒,你可以使用下面代码: ~~~ TimeUnit.SECONDS.toMillis(129) ~~~ TimeUnit更加强大,在需要使用sleep的时候,建议使用TimeUnit ## 2. yield ### 2.1 特性 yield属于一种启发式的方法,会提箱调度器表示当前线程原因放弃cpu资源,如果cpu资源不紧张,则会忽略这种题型。 ## 3. yield于sleep 1、sleep只是暂时停止,没有时间片的消耗 2、yield执行后,如果调度器没有忽略这个提示,则会导致上下文切换。 3、sleep可以捕捉到interrupt信号,yield不能 ### 3.1 wait和sleep的区别 一、wait特性: 1. 线程调用了某个对象的wait方法后,都会放入该对象monitor相关联的wait set 中,并释放monitor的所有权! 2. notify唤醒wait set中的一个thread,notifyall唤醒wait set中所有的阻塞线程,唤醒后仍需要争夺锁 二、wait和sleep的区别 1、wait是Object类的方法,所有类都有这个方法,sleep是Thread特有的方法 2、wait必须持有对象的monitor锁,也是就说wait必须在同步方法中执行 3、wait会释放锁,sleep不会释放锁 4、wait需要在同步方法中执行,sleep不需要。而且要求执行wait的方法和同步所用的锁关联对象是同一个。 ![](https://img.kancloud.cn/d3/f4/d3f41fb67920a455a156491bc08bf93d_635x302.png) 同步对象是this,但是调用MUTEX的wait方法,此时会抛出IllegalMonitorStateException! ### 3.2 wait和sleep的相同点 1、sleep和wait都是可中断方法,被打断后,都会收到中断异常InterruptdException,同时擦除interrupt标识 ## 4. interrupt ### 4.1 interrupt特性 1、只对由于wait,sleep,join等造成阻塞的线程起作用!对于没有阻塞的线程 不起作用 2、interrupt和stop不同的是,它不会终止整个线程,而是终止Object.wait, Thread.join和Thread.sleep三种方法造成的阻塞状态,果在调用它时,线程处于阻塞状态了,调用interrupt会抛出InterruptedException 3、打断一个线程并不是线程的生命周期的结束,而是打断了线程的阻塞状态 ~~~ package com.tuna.test.thread; public class InterruptThread1 extends Thread { public static void main(String[] args) { InterruptThread1 t = new InterruptThread1(); t.start(); try { Thread.sleep(1000); t.interrupt(); } catch (InterruptedException e) { e.printStackTrace(); } } @Override public void run() { for (int i = 0; i <= 200000; i++) { try { Thread.sleep(2000); System.out.println("i=" + i); } catch (InterruptedException e) { e.printStackTrace(); } } } } ~~~ 如下输出,中断异常后,不会影响线程的继续执行 ``` java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at com.tuna.test.thread.InterruptThread1.run(InterruptThread1.java:21) i=1 i=2 i=3 i=4 i=5 ... ``` **执行interrupted方法和可中断方法拦截InterruptedException后会擦出中断标记** ### 4.2 实例 ![](https://img.kancloud.cn/8e/4b/8e4ba2c36c0e46bea7cbd2d862f529d9_1160x676.png) 两毫秒后,主线程打断子线程的阻塞,子线程捕获中断异常,输出“Oh,i am be interrupted” ### 4.3 interrupt flag 1、每个线程都有一个interrupt flag,当调用线程被interrupt,该标记会被设置 2、当线程调用了可中断方法进入阻塞时,调用interrupt方法被调用,flag将会被清除,说明线程已经打断了interrupt状态(非阻塞),此时调用isInterrupted方法时,返回false。 ### 4.4 判断线程是否被中断 1、**isInterrupted** 判断线程是否被中断 ![](https://img.kancloud.cn/6a/9e/6a9e8df6605fea08491c68ba0e6489df_1253x631.png) ![](https://img.kancloud.cn/23/6e/236ed52fd94ee9db62efe3d13eaf9a99_611x116.png) **调用sleep可中断方法,进入阻塞** 第一次输出,因为没有被中断,所以输出false 第二、三输出时,线程被中断,但是**interrupt flag被擦除了**,依然输出false 2、 **interrupted** 判断是否被中断 1)如果线程被打断了,第一次调用interrupted将返回true,并立即擦除interrupt flag标记 2)第二次及以后调用interrupted都会返回false,除非次线程再一次被打断 ![](https://img.kancloud.cn/f3/2f/f32fd7dce0cb726e46b7b206e36ce20c_1050x567.png) 子线程不断输出,期间main线程打断了一下子线程,所以会输出一次true,并且马上擦擦除标记,继续输出 false。 由此看出,**interrupt不会影响非阻塞(可中断)的线程的继续执行** ## 5. join 阻塞线程,可中断 B调用A线程join方法,b进入阻塞,知道A执行完成 ## 6 线程进入runnable状态 1、阻塞I/O完成,比如网络i/o完成,进入runnable状态 2、完成了指定得休眠sleep,进入runnable状态 3、wait中的线程被其他线程notify/notifyall唤醒,进入runnable状态 4、获取到了某个锁资源,进入runnable状态 5、线程在阻塞过程中,被其他线程interrupted,进入runnable状态