Java没有提供任何机制来安全地(抢占式方法)终止线程,虽然Thread.stop和suspend等方法提供了这样的机制,但是由于存在着一些严重的缺陷,因此应该避免使用。但它提供了中断Interruption机制,这是一种协作机制,能够使一个线程终止另一个线程的当前工作。
一、任务取消
取消操作的原因:
. 用户请求取消
. 有时间限制的操作
. 应用程序事件
. 错误
. 关闭
. 用户请求取消
. 有时间限制的操作
. 应用程序事件
. 错误
. 关闭
结束任务的四种方式:
1. run方法执行结束
2. 使用请求关闭标记(例如boolean开关)
3. 使用中断机制
4. 使用Future退出方法
2. 使用请求关闭标记
当执行到并满足条件是使用return退出run方法
变量需要volatile确保变量多线程环境下的可见性。
-例子待填充,没有执行到判断条件就不会退出,所以不是立即退出的办法。
3. 使用中断机制
优点是相对“请求关闭标记”相应更快一些,但也不是立即关闭线程。
void interrupt() 中断线程。
boolean interrupted() 测试当前线程是否已经中断。
boolean isInterrupted() 测试线程是否已经中断。
InterruptedException异常
程序应该对线程中断作出恰当的响应。
// 1
Thread thread = new Thread("interrupt test") {
public void run() {
for (;;) {
doXXX();
if (Thread.interrupted()) {
break;
}
}
}
};
thread.start();
// 2
Thread thread = new Thread("interrupt test") {
public void run() {
for (;;) {
try {
doXXX();
} catch (InterruptedException e) {
break;
} catch (Exception e) {
// handle Exception
}
}
}
};
thread.start();
// 3
public void foo() throws InterruptedException {
if (Thread.interrupted()) {
throw new InterruptedException();
}
}
4. 使用Future退出方法
boolean cancel(boolean mayInterruptIfRunning)
试图取消对此任务的执行。
boolean isCancelled()
如果在任务正常完成前将其取消,则返回 true。
试图取消对此任务的执行。
boolean isCancelled()
如果在任务正常完成前将其取消,则返回 true。
*. 处理不可中断的阻塞
*. 采用newTaskFor来封装费标准的取消
二、停止基于线程的服务
之前的任务取消,主要是涉及如何关闭单个线程并且都是由创建单个线程的对象来进行关闭操作,但是如果线程不是由对象自己而是由线程池统一创建的线程该如何处理呢?
1. 使用线程的对象进行关闭 - 当前即使不在对象中创建线程而由线程池创建,这个对象依然可以关闭线程,这点一定要相信程序员的破坏能力,只是使用第2种方式更符合封装原则。
2. 使用线程池统一管理 - 如果是使用ExecutorService创建就交由其进行关闭操作。
2. 使用线程池统一管理(关闭ExecutorService)
void shutdown()
启动一次顺序关闭,执行以前提交的任务,但不接受新任务。如果已经关闭,则调用没有其他作用。
启动一次顺序关闭,执行以前提交的任务,但不接受新任务。如果已经关闭,则调用没有其他作用。
-- 安全关闭方式。
List<Runnable> shutdownNow()
试图停止所有正在执行的活动任务,暂停处理正在等待的任务,并返回等待执行的任务列表。
无法保证能够停止正在处理的活动执行任务,但是会尽力尝试。例如,通过 Thread.interrupt() 来取消典型的实现,所以任何任务无法响应中断都可能永远无法终止。
List<Runnable> shutdownNow()
试图停止所有正在执行的活动任务,暂停处理正在等待的任务,并返回等待执行的任务列表。
无法保证能够停止正在处理的活动执行任务,但是会尽力尝试。例如,通过 Thread.interrupt() 来取消典型的实现,所以任何任务无法响应中断都可能永远无法终止。
-- shutdownNow方法的局限性,强制关闭方式。
boolean isShutdown()
boolean isShutdown()如果此执行程序已关闭,则返回 true。
boolean isShutdown()如果此执行程序已关闭,则返回 true。
3. “毒丸”对象
只有在生产者消费者的数量都已知的情况下,才可以使用“毒丸”对象。
三、处理非正常的线程终止
Thread.UncaughtExceptionHandler全局的捕获的异常处理,通常在应用中用于异常的统计,收集到这些统计后可以对应用进行异常修复。
四、JVM关闭
1. 关闭钩子
Runtime.getRuntime().addShutdownHook(new Thread()) ;
void addShutdownHook(Thread hook)
注册新的虚拟机来关闭钩子。
注册新的虚拟机来关闭钩子。
2. 守护线程
希望创建一个线程来执行一些辅助工作,但又不希望这个线程阻碍JVM的关闭,可以使用守护线程。
3. 终结器
避免使用终结器finalize
五、参考资料:
"程序应该对线程中断作出恰当的响应" 摘录自
《温绍锦 - Java并发程序设计教程》