线程中断的方式
Java提供了线程的中断机制:设置线程的中断标志,我们可以使用它来结束一个线程。通过设置线程的中断标志并不能直接终止该线程的执行,这种机制要求线程自己检查它是否被中断了,然后决定是不是要相应这个中断请求。
线程中断相关的API
- void interrupt():中断线程,例如线程A运行时,线程B可以调用线程A的interrupt方法来设置线程A的中断标志位true。
注意:这里仅仅是设置了标志,线程A并没有中断,它会继续往下执行。
如果线程A调用了wait系列函数,join方法或sleep方法而被阻塞挂起,这时候如果线程B调用了线程A的interrupt()方法,线程A会在调用这些方法的地方抛出InterruptedException异常而返回。 - boolean isInterrupted():检测当前线程是否被中断,如果是返回true,否则返回false.
- boolean interrupted():
检测当前线程是否被中断
,如果是返回true,否则返回false;这个方法是Thread类的静态方法;另外与interrupt()方法的区别在于,如果发现当前线程被中断,则会清除中断 标志;另外需要注意的是:interrupted()方法是获取当前调用线程(正在运行的线程)的中断标志而不是调用interrupted()方法的实例对象的中断标志。(关键字:检测中断标志并清除中断标志
)
线程中断的示例
public class InterruptTest {
public static void main(String[] args) throws InterruptedException {
Thread threadA = new Thread(new Runnable() {
@Override
public void run() {
//如果线程没有被中断
while(!Thread.currentThread().isInterrupted()) {
System.out.println(Thread.currentThread() + "hello...");
}
if (Thread.currentThread().interrupted()) { //这里说明这个方法会清除中断标志
System.out.println(Thread.currentThread() + " interrupted flag is " + Thread.currentThread().isInterrupted());
}
}
});
//启动子线程
threadA.start();
//主线程休眠1s,以便于中断前让子线程输出
Thread.sleep(1000);
System.out.println("main thread interrupt thread");
threadA.interrupt();
//等待子线程执行完毕
threadA.join();
System.out.println("main is over");
}
}
输出结果:
Thread[Thread-0,5,main]hello…
Thread[Thread-0,5,main]hello…
Thread[Thread-0,5,main]hello…
Thread[Thread-0,5,main]hello…
main thread interrupt thread
Thread[Thread-0,5,main]hello…
Thread[Thread-0,5,main]hello…
Thread[Thread-0,5,main]hello…
Thread[Thread-0,5,main]hello…
Thread[Thread-0,5,main]hello…
Thread[Thread-0,5,main]hello…
Thread[Thread-0,5,main]hello…
Thread[Thread-0,5,main] interrupted flag is false
main is over
代码说明:
if (Thread.currentThread().interrupted()) { //这里说明这个方法会清除中断标志
System.out.println(Thread.currentThread() + " interrupted flag is " + Thread.currentThread().isInterrupted());
}
//这种写法和下面的写法作用是一样的,这两种写法都是说明要为当前正在执行的线程设置中断标志
if (Thread.interrupted()) { //这里说明这个方法会清除中断标志
System.out.println(Thread.currentThread() + " interrupted flag is " + Thread.currentThread().isInterrupted());
}
sleep过程中被打断
补充一下场景:当线程为了等待一些特定的条件的到来,一般会调用sleep函数、wait系列函数或者join()函数来阻塞挂起当前线程。那举例来说,一个线程条用sleep函数休眠10s来等待条件满足,但是它可能等了3秒条件就满足了,一直等到10s有点浪费时间,这个时候就可以调用该线程的interrupt()方法,强制sleep方法抛出InterruptedException异常而返回,线程回复到激活状态。
public class SleepInterrupt {
public static void main(String[] args) throws InterruptedException {
Thread threadA = new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println("threadA begin to sleep for 2000 seconds");
Thread.sleep(2000000);
System.out.println("threadA awaking");
}
catch (InterruptedException e) {
System.out.println("threadA is interrupted while sleeping");
return;
}
System.out.println("threadA leaving normally");
}
});
threadA.start();
//确保子线程进入休眠状态
Thread.sleep(1000);
//打断子线程
threadA.interrupt();
//等待子线程执行完毕
threadA.join();
System.out.println("main thread is over");
}
}
程序输出:
threadA begin to sleep for 2000 seconds
threadA is interrupted while sleeping
main thread is over
interrupted vs interrupt
public class interruptedTest {
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:" + Thread.interrupted());
//获取中断标志
System.out.println("isInterrupted:" + threadOne.isInterrupted());
threadOne.join();
System.out.println("main thread is over");
}
}
程序输出:
isInterrupted:true
isInterrupted:false
isInterrupted:true
分析:第一行输出是因为threadOne.interrupt();设置了threadOne的中断标志;
第二行输出:因为Thread.interrupted()判断的是当前正在执行的线程,也可就是主线程的中断标志;
第三行输出:因为这里判断的也是threadOne的中断标志;
最终threadOne并没有被中断还是一直在空跑,因此最终main thread is over也没有输出。
下面修改下程序:
public class interruptedTest {
public static void main(String[] args) throws InterruptedException {
Thread threadOne = new Thread(new Runnable() {
@Override
public void run() {
//中断标志位true就会退出循环,并且清除中断标志
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");
}
}
程序输出:
threadOne isInterrupted:false
main thread is over
分析:第一行输出,因为执行了threadOne.interrupt();之后threadOne中再执行interrupted()方法,可以检测到线程被设置了中断标志,再执行Thread.currentThread().isInterrupted()检测不出中断标志了,因为被while条件里面的interrupted()方法中断了。
第二行输出,因为threadOne执行完之后,threadOne.join()返回了,main线程不再阻塞,继续执行了下面的语句,输出了main thread is over