线程中断
线程中断的概念
疑问:杀毒软件没完成时,点击取消按钮,杀毒软件立刻就会退出吗?
错误理解:被中断的线程立刻退出
概念
-
1.java中线程中断是一种协作机制
-
2.通过中断并不能直接终止线程的运行
-
3.需要被中断的线程自己处理中断
例:父母叮嘱在外孩子注意身体,但是是否注意身体,完全取决于孩子 -
每个线程有一个boolean类型的标志位,代表线程是否中断
-
线程1想中断线程2,线程1只需要设置线程2的中断标识为true
-
线程2在合适的时候处理中断请求,甚至线程2可以选择不处理中断请求
线程中断相关方法
- 1.public static boolean interrupted()
测试当前线程是否中断,线程的中断状态由该方法清除。
如果连续两次调用该方法,则第二次调用将返回false。
在第一次调用已清除了其中断状态之后,且第二次调用检验完中断状态前
可以对当前线程再次中断 - 2.public boolean isInterrupted()
测试线程是否已经中断,线程的中断不受该方法影响 - 3.public void interrupt()
将调用该方法的对象所表示的线程标记一个停止标记,并不是真正停止该线程
intertupt()是唯一能将中断状态设置为true的方法,interrupted()会将中断状态清除
中断的处理
- 1.方法声明中有抛出InterruptedException则表示该方法是可中断的
- 2.常见的抛出InterruptedException异常的方法:
a.Object.wait()
b.Thread.sleep()
c.BlockQueue.put()
d.BlockQueue.take() - 3.java中只能设置线程的中断状态,那被中断的线程应该做什么?
视情况而定
可以立即终止,或者执行完再终止
如果不确定调用interrupt()后该线程会做出什么样的响应,那就不应该中断该线程
抛出InterruptedException
如果抛出InterruptedException意味着一个方法是阻塞方法,
那么调用一个阻塞方法意味着你的方法也是一个阻塞方法
通常最容易的策略是自己抛出InterruptedException
package com.hexy.thread.demo;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
/***
* 任务队列,封装了LinkedBlockingQueue
*/
public class ThreadDemo4<T> {
private static final int MAX_TASKS = 1000;
private BlockingQueue<T> queue = new LinkedBlockingQueue<>(MAX_TASKS);
public void putTask(T t)throws InterruptedException{
queue.put(t);
}
public T getTask()throws InterruptedException{
return queue.take();
}
}
## 中断的响应
捕获异常再抛出
有时候需要在传播异常之前进行一些清理工作,
这种情况下看,可以捕获InterruptedException,执行清理,然后抛出异常
package com.hexy.thread.demo;
/**
* 捕获中断异常并抛出
*/
public class ThreadDemo5 {
public static void main(String[] args) throws InterruptedException{
Thread thread = Thread.currentThread();
try {
thread.interrupt();
Thread.sleep(3000);
}catch (InterruptedException e){
//做一些清理工作
System.out.println("做一些清理工作");
throw e;
}
}
}
重新中断
- 有时候代码里直接抛出InterruptedException不合适
- 如Runnable借口的run()方法不允许抛出异常
- 如果线程运行中出现了InterruptedException,又不能抛出异常
- 直接捕获异常,可能又没办法通知上层代码,又不能保留中断的证据
- 比价好的方式是再次调用interrupt()方法重新中断
package com.hexy.thread.demo;
/**
* 重新设置中断
*/
public class ThreadDemo6 extends Thread {
public static void main(String[] args) throws InterruptedException {
Thread thread = new ThreadDemo6();
System.out.println("starting thread");
thread.start();
Thread.sleep(3000);
System.out.println("asking thread to sleep");
thread.interrupt();
Thread.sleep(3000);
System.out.println("stopping application");
}
@Override
public void run(){
while(!Thread.currentThread().isInterrupted()){
//循环等待线程中断
System.out.println("Thread Running");
try {
//应该会执行3次
//线程阻塞,如果线程收到中断操作信号将抛出异常
Thread.sleep(1000);
}catch (InterruptedException e){
System.out.println("thread interrupted..");
//false
System.out.println(this.isInterrupted());
//中不中断由自己决定,如果需要真的中断线程,则需要重新设置中断位
//如果不需要则不调用
Thread.currentThread().interrupt();
}
}
System.out.println("interrupted ... "+this.isInterrupted());
System.out.println("thread exiting");
}
}