这是我参与11月更文挑战的第9天,活动详情查看:2021最后一次更文挑战
Java中的线程中断是一种线程间的协作模式,通过设置线程的中断标志并不能直接终止该线程的执行,而是被中断的线程根据中断状态自行处理。
void interrupt()方法: 中断线程,例如当线程A运行时,线程B可以调用线程A的interrupt()方法来设置线程A的中断标志为true并立即返回。设置标志仅仅是设置标志,线程A实际上并没有被中断,它继续往下执行。如果线程A调用了wait()、sleep()、join()方法而被阻塞,这时候线程B调用线程A的interrupt()方法,线程A会抛出InterruptedException异常。
boolean isInterrupted()方法: 检测当前线程是否被中断,如果是则返回true。
public static boolean isInterrupted() {
//传递flase说明不清除中断标志
return isInterrupted(false);
}
boolean interrupted()方法: 检测当前线程是否被中断,如果是返回true。与isInterrupted不同的是,该方法如果发现当前线程被中断,则会清除中断标志,并且该方法是static方法,可以通过Thread类直接调用。在interrupted内部是获取当前调用线程的中断标志而不是调用interrupted方法的实例对象的中断标志。
public static boolean interrupted() {
//清除中断标志
return currentThread().isInterrupted(true);
}
下面看一个根据中断标志判断线程是否终止的例子:
public class interruptest1 {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// 如果当前线程被中断则退出循环
while (!Thread.currentThread().isInterrupted()) {
System.out.println(Thread.currentThread() + " hello");
}
}
});
//启动子线程
thread.start();
// 主线程休眠1s,以便中断前让子线程输出
Thread.sleep(1000);
System.out.println("main thread interrupt thread");
thread.interrupt();
// 等待子线程执行完毕
thread.join();
System.out.println("main is over");
}
}
输出如下:
接下来再看一个例子。当线程为了等待一些特定条件的到来时,一般会调用sleep、wait或者join方法来阻塞挂起线程。但如果在某个时间点提前满足返回条件时,可以使用线程的interrupt方法,强制抛出InterruptedException异常而返回。
public class interruptest2 {
public static void main(String[] args) throws InterruptedException{
Thread threadOne = new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println("threadOne begin sleep for 2000 seconds");
Thread.sleep(200000);
System.out.println("threadOne awaking");
} catch (InterruptedException e) {
System.out.println("threadOne is interrupted while sleeping");
return;
}
System.out.println("threadOne-leaving normally");
}
});
//启动线程
threadOne.start();
//确保子线程进入休眠状态
Thread.sleep(1000);
//打断子线程休眠,让子线程从sleep返回
threadOne.interrupt();
//等待子线程执行完毕
threadOne.join();
System.out.println("main is over");
}
}
输出如下:
我们再通过一个例子来了解interrupted()和isInterrupted()的区别。
public class interruptest3 {
public static void main(String[] args) throws InterruptedException{
Thread threadOne = new Thread(new Runnable() {
@Override
public void run() {
for(;;) {
}
}
});
//启动线程
threadOne.start();
//设置中断标志
threadOne.interrupt();
//获取中断标志
System.out.println("isInterrupted: " + threadOne.isInterrupted());
//获取中断标志,并重置
System.out.println("isInterrupted: " + threadOne.interrupted());
//获取中断标志,并重置
System.out.println("isInterrupted: " + Thread.interrupted());
//获取中断标志
System.out.println("isInterrupted: " + threadOne.isInterrupted());
threadOne.join();
System.out.println("main thread is over");
}
}
结果如下:
这是因为interrupted()方法获取的是当前线程的中断状态而不是threadOne线程的中断状态。 所以结果为true、 false、 false、 true。
而如果我们将代码修改如下后显然输出为flase,因为调用interrupted()后,中断标志被清除了:
public class interrupt4 {
public static void main(String[] args) throws InterruptedException{
Thread threadOne = new Thread(new Runnable() {
@Override
public void run() {
while(!Thread.currentThread().interrupted()) {
}
System.out.println("threadOne isInterrupted:" + Thread.currentThread().isInterrupted());
}
});
//启动线程
threadOne.start();
//设置中断标志
threadOne.interrupt();
threadOne.join();
System.out.println("main thread is over");
}
}