中断线程--JCIP7.1读书笔记
[本文是我对Java Concurrency In Practice 7.1的归纳和总结. ?转载请注明作者和出处, ?如有谬误, 欢迎在评论中指正. ]
启动线程之后, 大多数时候我们等待线程运行完成后自动结束. 但是有时我们希望可以提前终止线程的运行:
1. 用户申请取消时. 比如用户点击了取消按钮.
2. 时间限制的任务. 有些任务具有时间限制, 如果在一定的时间内仍然没有得到想要的结果, 我们可能希望终止该任务的运行.
3. 发生特定的事件时. 比如多个线程同时在不同的位置搜索某一文件, 当其中一个线程搜索到了想要的文件, 应该终止其他仍在运行的线程.
4. 发生错误时. 比如发生了磁盘已满的错误, 需要向磁盘写入数据的线程应该提前终止.
5. 应用或者服务被关闭时.
?
java没有直接规定如何安全的提前终止线程的运行, 相反, 提供了不具约束力的协商式机制: 线程A可以请求线程B中断, 但是是否响应, 何时响应, 如何响应中断请求, 由线程B自己决定. 每个线程对象都有一个boolean型的中断标记, 其他线程请求目标线程中断时, 会将目标线程的中断标记设置为true, 然后由目标线程自己决定如何处理. 所以中断线程时, 我们需要知道目标线程的中断机制. 如果我们不知道目标线程会怎样处理中断请求, 不要贸然请求其中断. Thread类中与中断标记相关的方法有:
/** * 执行一项任务, 如果指定时间内没有正常完成, 就取消该任务 */public static void timedRun(Runnable r, long timeout, TimeUnit unit) throws InterruptedException {Future<?> task = taskExec.submit(r);try {// 如果线程池中的线程执行任务过程中该线程发生了中断, 那么调用task的get方法将会抛出InterruptedException异常.// 对于InterruptedException, 按照之前总结的方法处理即可. 此例将其抛给上层.task.get(timeout, unit);} catch (TimeoutException e) {// 如果发生TimeoutException异常, 表明执行时间超时, 此时取消该任务即可} catch (ExecutionException e) {// 发生其他异常时, 不仅要取消任务的执行, 也应该重抛该异常throw launderThrowable(e.getCause());} finally {task.cancel(true);}}?
线程的中断方式总结:
1. 可以通过设置自定义标记结束线程. 但是这样方式在包含阻塞方法的任务中不适用.
2. interrupt线程. 前提是知道目标线程会怎样处理interrupt请求.
3. 如果是提交给线程池运行的任务, 可以调用Future.cancel.
?