java提供了2种取消线程的方法。第一种是stop,这个已经不再推荐使用。第二种是Interrupt,目前的主要推荐的手段。在日常开发中,stop是比较暴力的,可以直接停掉线程,Interrupt则是需要代码编写做一些事情。
stop
stop虽然比较直接,但是应用的场景是比较有限的。只适合线程操作比较单一的情况。直接杀掉线程有以下2个问题。
- 资源无法回收。
例如线程正在读取文件,外部调用了stop,线程就会立马停止。已经被打开的文件句柄在线程内无法释放,jdk只有在对象gc的时候,用担保的手段做资源的回收,但是没有触发gc之前,发生了资源的泄露,对后续资源的使用带来了不太好追踪的bug。 - 对于再次开启线程的情况无法处理
stop只是停掉了当前的线程,如果线程里的操作是继续提交任务给线程池。那么在逻辑层面,stop是需要把已经提交的任务也取消的。stop停止线程后,线程池里的任务还是会执行完毕,导致了资源的浪费。
interrupt
interrupt只是提供了一种消息通知机制。并不会直接停止掉线程。程序员在写代码的时候,需要明确的写可中断的代码,当遇到interrupt的时候,需要对应的代码做操作。代码风格如下。对于可中断的部分操作。必须先做线程是否中断,要编写中断的逻辑,例如释放资源,取消生成的task等等。
if (Thread.currentThread().isInterrupted()) {
xxx
}
jdk的很多方法都会抛出InterruptedException,例如sleep。发生中断时会直接停止操作,然后抛出异常。对于jdk自带的方法。需要格外注意。
IllegalArgumentException – if the value of millis is negative
InterruptedException – if any thread has interrupted the current thread. The interrupted status of the current thread is cleared when this exception is thrown.
我们在方法的声明中可以看到The interrupted status of the current thread is cleared when this exception is thrown.抛出这个异常的时候,同时会把标志位清除。所以在捕获了InterruptedException的同时,必须再次设置标志位,否则后续的判断都会失效。
Thread.interrupted();
future取消
java常用的提交任务给线程池,然后返回future,future是带了取消操作的。
public boolean cancel(boolean mayInterruptIfRunning) {
if (!(state == NEW &&
UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
return false;
try { // in case call to interrupt throws exception
if (mayInterruptIfRunning) {
try {
Thread t = runner;
if (t != null)
t.interrupt();
} finally { // final state
UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
}
}
} finally {
finishCompletion();
}
return true;
}
参数中的mayInterruptIfRunning就是是否调用interrupt去中断已经执行的线程。
future取消会先尝试把状态,从New改成INTERRUPTING或者CANCELLED。这里对应的是提交了任务,但是任务还没被执行的时候,只要更改了状态。线程池拿到future执行,future会看状态已完成就直接返回,线程池可以继续调度其他future。
下面的interrupt对应的是已经执行的任务。如果任务已经执行中了,会调用interrupt发出信号。对应的线程里只要有取消的操作,就可以取消。但是如果没有这样的操作。那么还是会执行完。只是future这边会把状态标志完成。线程池的里的线程资源依旧会占用。
总结
- stop方法简单粗暴,如果线程里都是单线程的运算任务,他的功能是满足需要的。但是涉及到退出逻辑,他的操作反而会带来风险。
- interrupt只是发出信号。对应的线程的代码需要做信号的捕捉,以此保证退出释放的逻辑正确。
- future的取消是用interrupt实现的。如果想做到及时的释放资源,那么编写的代码,是需要有信号判断的。
共同学习,写下你的评论
评论加载中...
作者其他优质文章