Java并发编程实战 第6章 任务并行 第7章 取消与关闭
ExecutorCompletionService
CompletionService用来接收一个Executor的执行结果,将已经完成任务,放置在可使用 take 访问的队列上。
大概用法:
Executor e = Executors. newCachedThreadPool();
CompletionService<Result> ecs = new ExecutorCompletionService<Result>(e);
List< Callable<Result> > solvers;
for (Callable<Result> s : solvers)
{
ecs.submit(s);
}
for (int i = 0; i < solvers.size(); ++i) {
Result r = ecs.take().get();
}
关闭钩子
Runtime. getRuntime().addShutdownHook
注册新的虚拟机关闭挂钩。
Java 虚拟机会为了响应以下两类事件而关闭:
程序正常退出,这发生在最后的非守护线程退出时,或者在调用 exit(等同于System.exit)方法时。或者,
为响应用户中断而终止 虚拟机,如键入 ^C;或发生系统事件,比如用户注销或系统关闭。
关闭挂钩 只是一个已初始化但尚未启动的线程。虚拟机开始启用其关闭序列时,它会以某种未指定的顺序启动所有已注册的关闭挂钩,并让它们同时运行。运行完所有的挂钩后,如果已启用退出终结,那么虚拟机接着会运行所有未调用的终结方法。最后,虚拟机会暂停。注意,关闭序列期间会继续运行守护线程,如果通过调用 exit 方法来发起关闭序列,那么也会继续运行非守护线程。
一旦开始了关闭序列,则只能通过调用 halt 方法来停止这个序列,此方法可强行终止虚拟机。
一旦开始了关闭序列,则不可能注册新的关闭挂钩或取消注册先前已注册的挂钩。尝试执行这些操作会导致抛出 IllegalStateException。
关闭挂钩可在虚拟机生命周期中的特定时间运行,因此应保护性地对其进行编码。特别是应将关闭挂钩编写为线程安全的,并尽可能地避免死锁。关闭挂钩还应该不盲目地依靠某些服务,这些服务可能已注册了自己的关闭挂钩,所以其本身可能正处于关闭进程中。
关闭挂钩应该快速地完成其工作。当程序调用 exit 时,虚拟机应该迅速地关闭并退出。由于用户注销或系统关闭而终止虚拟机时,底层的操作系统可能只允许在固定的时间内关闭并退出。因此在关闭挂钩中尝试进行任何用户交互或执行长时间的计算都是不明智的。
与其他所有线程一样,通过调用线程 ThreadGroup 对象的 uncaughtException 方法,可在关闭挂钩中处理未捕获的异常。此方法的默认实现是将该异常的堆栈跟踪 (stack trace) 打印至 System.err 并终止线程;它不会导致虚拟机退出或暂停。
参数:
hook - 一个已初始化但尚未启动的 Thread 对象
抛出:
IllegalArgumentException - 如果指定的挂钩已注册,或者可以确定挂钩正在运行或者已运行完毕
IllegalStateException - 如果虚拟机已经处于关闭进程中
SecurityException - 如果安全管理器存在并且拒绝 RuntimePermission("shutdownHooks")