1. 什么是中断
线程中断可以理解为线程的一个标识性属性。中断好比其他线程对该线程打了个“招呼“。中断后具体该如何操作取决于线程本身。
线程中断的几个重要方法:
// Thread 类中的实例方法,返回该线程的中断标识位的值
public boolean isInterrupted() {}
// Thread 中的静态方法,检测调用这个方法的线程是否已经中断
// 注意:这个方法返回中断状态的同时,会将此线程的中断状态重置为 false
// 所以,如果我们连续调用两次这个方法的话,第二次的返回值肯定就是 false 了
public static boolean interrupted() {}
// Thread 类中的实例方法,用于设置一个线程的中断状态为 true
public void interrupt() {}
看一个具体的例子:
package com.dcj.chapter5;
import com.dcj.SleepUtils;
public class InterruptTest {
public static void main(String[] args) {
Thread t = Thread.currentThread();
//中断该线程
t.interrupt();
System.out.println(t.isInterrupted()); //true
//检测调用该方法的线程是否已经中断//会重置中断状态为false
System.out.println("Thread.interrupted():" + Thread.interrupted()); //true, 但是会将中断状态设置为false
System.out.println("t.isInterrupted():" + t.isInterrupted()); //false
System.out.println("Thread.interrupted():" + Thread.interrupted()); //第二次调用,当然是false了
//中断状态被重置了
System.out.println("t.isInterrupted():" + t.isInterrupted());
//中断不影响线程本身执行,仍然可以打印
System.out.println(t);
Thread t1 = new Thread(() -> {
try {
Thread.sleep(10000); //sleep方法会响应中断,所以中断后catch块会被执行
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t1.start();
SleepUtils.second(4);
t1.interrupt();
}
}
以下方法在线程被中断时,可以自动的被感知到中断:
Object 类的 wait()、wait(long)、wait(long, int)
Thread 类的 join()、join(long)、join(long, int)、sleep(long)、sleep(long, int)
当这些状态被感知到时抛出异常时,当前线程的中断状态会被clear掉,也就是变为false.
2. InterruptedException
java中的wait, sleep 等都是阻塞方法,调用该方法后该线程会被阻塞等待唤醒。假如在阻塞等待的过程中,另外一个线程对该线程进行了中断,那么被中断的线程起码能知道这个被中断的信息。具体如何处理这个信息,要么捕获异常,要么继续往上抛出异常,这就有了InterruptedException。当抛出异常时,当前线程的中断状态会被clear掉。
3. 如何优雅的处理InterruptedException
对于这种抛出InterruptedException的方法,比如 lockInterruptibly.lockInterruptibly() 方法,其实现类是这样的:
#在方法的开头就做判断
public final void acquireInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
//接下来的代码
}
可以这么理解,获取锁的方法是一个阻塞方法,因为获取不到锁当前线程会挂起,但是我在刚开始执行的时候,该线程已经被中断了,那么就直接抛出异常给调用者。