java并发编程实战-第7章-取消与关闭
java中没有一种安全的抢占式方式的,只有协作式
取消标志如果和阻塞方法一起使用,则会失效,如
public void run() {
try {
BigInteger p = BigInteger.ONE;
while (!cancelled)
queue.put(p = p.nextProbablePrime());
} catch (InterruptedException consumed) { }
}
public void cancel() { cancelled = true; }
如果任务代码可以响应中断,则可以使用中断作为取消机制
7.1.2 中断策略
形式 :线程级 服务级
只有实现了线程中断策略的代码才可以屏蔽中断请求,在常规的任务和库代码中不应该屏蔽中断请求
7.1.6 处理不可中断的取消
public void interrupt() {
try {
socket.close();
}
catch (IOException ignored) { }
finally {
super.interrupt();
}
}
7.1.7 采用newTaskFor来封装非标准的取消
这是java 6 在ThreadPoolExecutor中的新增功能,这是个工厂方法,创建Future来代表任务,返回
RunnableFutrure接口,改接口扩展了Future和Runnable(并由FutureTask实现)
ThreadPoolExecutor中的cancel是调用newTaskFor返回的FunnableFutrure来取消操作的
通过定制Future 改变Future.cancel的行为,通过改写newTaskFor方法
ThreadPoolExecutor在哪里调用到了Future的cancel方法呢?
父类:AbstractExecutorService 在invokeAll 等invokeXXX方法中的最后finally
...
finally {
if (!done)
for (Future<T> f : futures)
f.cancel(true);
}
7.2 停止基于线程的服务
应用程序拥有服务,服务拥有线程,应用程序没有直接拥有线程,所以不能通过应用程序关闭线程,相反,
服务应该提供生命周期的方法。
比如,ExcutorService提供shutdown 和shiutdownNow方法
7.2.1 示例:日志服务
生产者-消费者
在关闭时候需要给一个isShutDown标志
Loger在消费时判断isShutDown需要同步,生产者在loger的queue.put(msg)的时候也需要同步
如果关闭后,队列中还有内容,则loger还得继续记录日志,用reservations 来计数
7.2.2 关闭ExecutorService
所有权链
使用ExecutorService的日志服务,比7.2.1的示例方面简洁多了
7.2.3 ”毒丸“对象
关闭生产者-消费者的一种方式
毒丸功能和7.2.1 中reservations一样,提供是否还有任务的标志
只有在生产者和消费者都已知的情况下才使用毒丸
7.2.4 示例:只执行一次的服务
7.2.5 shutdownNow的局限性
该方法能返回已提交但未开始的任务,但不会返回关闭时已经开始正在执行的任务
可以用继承的方式扩展功能,添加getCancelledTasks()方法
public class TrackingExecutor extends AbstractExecutorService {
private final ExecutorService exec;
private final Set<Runnable> tasksCancelledAtShutdown =
Collections.synchronizedSet(new HashSet<Runnable>());
...
public List<Runnable> getCancelledTasks() {
if (!exec.isTerminated())
throw new IllegalStateException(...);
return new ArrayList<Runnable>(tasksCancelledAtShutdown);
}
public void execute(final Runnable runnable) {
exec.execute(new Runnable() {
public void run() {
try {
runnable.run();
} finally {
if (isShutdown()
&& Thread.currentThread().isInterrupted())
tasksCancelledAtShutdown.add(runnable);
}
}
});
}
// delegate other ExecutorService methods to exec
}
7.3 处理非正常的线程终止
在GUI丢失事件分派线程的时候情况比较严重,应用程序停止处理事件,GUI停止响应
典型的线程池工作者结构,
public void run() {
Throwable thrown = null;
try {
while (!isInterrupted())
runTask(getTaskFromWorkQueue());
} catch (Throwable e) {
thrown = e;
} finally {
threadExited(this, thrown);
}
}
工作原理:当捕捉到未检测异常时,会终止该线程,但在终止之前,会通知框架,然后由框架来决定是否
用新线程代替或者用线程池的其它线程代替,
ThreadPoolExcutor和Swing都是通过该技术来确保糟糕的任务不会影响到后续任务的执行
7.3.1 未捕获异常的处理UncaughtExceptionHandler
该方法与如上的主动获取方法互补,UncaughtExceptionHandler如何处理异常取决于服务质量的需
求,最常见的是把错误信息以及相应的栈追踪信息写入到应用程序日志中
Listing 7.25. UncaughtExceptionHandler that Logs the Exception.
public class UEHLogger implements Thread.UncaughtExceptionHandler {
public void uncaughtException(Thread t, Throwable e) {
Logger logger = Logger.getAnonymousLogger();
logger.log(Level.SEVERE,
"Thread terminated with exception: " + t.getName(),
e);
}
}
If you want to be notified when a task fails due to an exception so that you can take some
task-specific recovery action,
either wrap the task with a Runnable or Callable that catches the exception or override the
afterExecute hook in THReadPoolExecutor.
令人困惑的:异常提交给UncaughtExceptionHandler ,只有对于execute有效,对submit无效,如果
submit提交的任务抛出了异常,那么这个异常将被Future.get封装在ExecutionException中重新抛出
参考:zhouchaofei2010.iteye.com/blog/2128389 源代码分析为什么ThreadPoolExcutor的Submit方法不
会把运行时的异常交给UncaughtExceptionHandler处理
7.4 JVM 关闭
7.4.1 关闭钩子
正常关闭:调用关闭钩子
Listing 7.26. Registering a Shutdown Hook to Stop the Logging Service.
public void start() {
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
try { LogService.this.stop(); }
catch (InterruptedException ignored) {}
}
});
}
非正常:
7.4.2 守护线程
在jvm启动过程中创建的线程。除了主线程,其他的都是守护线程
应少用守护线程,因为jvm 关闭时,守护线程会被抛弃,既不会执行finally代码块,也不会执行回卷栈
7.4.3 终结器
避免使用终结器,用finally代码块或显示close()代替
小结:
java中没有一种安全的抢占式方式的,只有协作式,要依赖于协议与是否遵守这些协议
Using FutureTask and the Executor framework simplifies building cancellable tasks
FutureTask 既可以在ExcutorService中使用,也可以再Thread 中使用
相关推荐
第7章 取消与关闭 第8章 线程池的使用 第9章 图形用户界面应用程序 第三部分 活跃性、性能与测试 第10章 避免活跃性危险 第11章 性能与可伸缩性 第12章 并发程序的测试 第四部分 高级主题 第13章 显式锁 第...
《Java并发编程实践》是Java开发者深入理解并发编程的重要参考资料,尤其对于想要提升多线程应用设计和性能优化技能的程序员来说,这本书提供了丰富的实践经验和深入的理论知识。以下是根据提供的章节内容概述的一些...
Java并发编程实战,第1章 简介,第2章 线程安全性 第3章 对象的共享 第4章 对象的组合 第5章 基础构建模块 第6章 任务执行 第7章 取消与关闭 第8章 线程池的使用 第9章 图形用户界面应用程序 第10章 避免...
第7章 取消与关闭 第8章 线程池的使用 第9章 图形用户界面应用程序 第三部分 活跃性、性能与测试 第10章 避免活跃性危险 第11章 性能与可伸缩性 第12章 并发程序的测试 第四部分 高级主题 第13章 显式锁 第...
│ Java并发编程.png │ ppt+源码.rar │ 高并发编程第二阶段01讲、课程大纲及主要内容介绍.wmv │ 高并发编程第二阶段02讲、介绍四种Singleton方式的优缺点在多线程情况下.wmv │ 高并发编程第二阶段03讲、...
龙果 java并发编程原理实战 第2节理解多线程与并发的之间的联系与区别 [免费观看] 00:11:59分钟 | 第3节解析多线程与多进程的联系以及上下文切换所导致资源浪费问题 [免费观看] 00:13:03分钟 | 第4节学习并发的四...
第7章 取消和关闭 7.1 任务取消 7.2 停止基于线程的服务 7.3 处理反常的线程终止 7.4 JVM关闭 第8章 应用线程池 8.1 任务与执行策略问的隐性耦合 8.2 定制线程池的大小 8.3 配置ThreadPoolExecutor 8.4 扩展...
第1章介绍Java并发编程的挑战,向读者说明进入并发编程的世界可能会遇到哪些问题,以及如何解决。 第2章介绍Java并发编程的底层实现原理,介绍在CPU和JVM这个层面是如何帮助Java实现并发编程的。 第3章介绍深入介绍...
随书附带的`concurrentbook`和`concurrentbook-jdk7`文件夹可能包含了与上述知识点对应的示例代码,通过阅读和运行这些代码,读者可以更好地理解和掌握Java并发编程的实际应用。在实践中不断探索和调试,将有助于...
《Java并发编程的艺术》笔记 第一章 并发编程的挑战 第二章 Java并发机制的底层实现原理 volatile的两条实现原则: 1. Lock前缀指令会引起处理器缓存回写到内存 2. 一个处理器的缓存回写到内存会导致其他...
#### 十一、并发编程实战与故障排查 最后一章提供了一些并发编程的实际案例,并探讨了如何排查并发编程中可能出现的问题。这些案例涵盖了各种常见场景,从简单的同步问题到复杂的竞态条件等。通过分析这些案例,...
│ Java并发编程.png │ ppt+源码.rar │ 高并发编程第二阶段01讲、课程大纲及主要内容介绍.wmv │ 高并发编程第二阶段02讲、介绍四种Singleton方式的优缺点在多线程情况下.wmv │ 高并发编程第二阶段03讲、...
### Java并发编程实践笔记知识点详解 #### 一、保证线程安全的方法 1. **不要跨线程访问共享变量:** 当多个线程共享某个变量时,若其中一个线程修改了该变量,其他线程若没有正确同步,则可能读取到错误的数据。...
java并发编程原理实战 第2节理解多线程与并发的之间的联系与区别 [免费观看] 00:11:59分钟 | 第3节解析多线程与多进程的联系以及上下文切换所导致资源浪费问题 [免费观看] 00:13:03分钟 | 第4节学习并发的四个...