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 中使用
相关推荐
《Java并发编程实践》是Java开发者深入理解并发编程的重要参考资料,尤其对于想要提升多线程应用设计和性能优化技能的程序员来说,这本书提供了丰富的实践经验和深入的理论知识。以下是根据提供的章节内容概述的一些...
第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 扩展...
│ Java并发编程.png │ ppt+源码.rar │ 高并发编程第二阶段01讲、课程大纲及主要内容介绍.wmv │ 高并发编程第二阶段02讲、介绍四种Singleton方式的优缺点在多线程情况下.wmv │ 高并发编程第二阶段03讲、...
### Java并发编程实践笔记知识点详解 #### 一、保证线程安全的方法 1. **不要跨线程访问共享变量:** 当多个线程共享某个变量时,若其中一个线程修改了该变量,其他线程若没有正确同步,则可能读取到错误的数据。...
java并发编程原理实战 第2节理解多线程与并发的之间的联系与区别 [免费观看] 00:11:59分钟 | 第3节解析多线程与多进程的联系以及上下文切换所导致资源浪费问题 [免费观看] 00:13:03分钟 | 第4节学习并发的四个...
第5、6、9章则主要参考了Brian Goetz的《Java并发编程实战》,提供了实战中的并发解决方案。第7章整理自网络博客,汇集了社区中的优秀实践和见解。第8章则是基于我司的多线程项目经验,提炼出的实际案例,相关代码可...
10. **并发编程实战**:提供实际案例分析和练习,帮助读者将理论知识应用于实际项目,增强解决并发问题的能力。 11. **分布式并发**:简述在分布式系统中的并发问题,如分布式锁、分布式协调服务(如Zookeeper)...
《Java高并发编程》第一版是一本专注于...通过阅读《Java高并发编程》第一版,开发者不仅可以掌握Java并发编程的核心概念和技术,还能了解到如何在实际工作中设计和实现高效、安全的并发程序,提升系统的并发处理能力。
《Java并发编程实践》这本书是Java开发者深入理解并发编程的重要参考资料。它涵盖了从基础到高级的并发编程概念,旨在帮助读者提升在多线程环境下的编程能力,优化系统性能,避免并发问题。以下是对该书内容的详细...
11. 第11章提供并发编程实战案例,介绍问题排查方法。 本书适合已有一定Java基础和开发经验的读者,特别是Java开发工程师、架构师和并发编程爱好者。初学者可以按顺序阅读并实践书中的例子,有经验的读者则可根据...
第7章介绍了Java中原子操作类的使用,展示了如何通过原子类实现无锁的线程安全操作。第9章则从原理和使用建议两方面介绍了线程池的实现,为读者提供了构建高效并发应用的实用技巧。 Executor框架作为Java并发编程的...
《Java并发编程实践》是一本深入探讨Java多线程编程的权威著作,它详细阐述了在并发环境下如何设计和实现高效、可靠的程序。这本书涵盖了Java并发编程的核心概念、工具和最佳实践,对于想要提升Java并发编程技能的...
1. **Java并发基础**:介绍Java并发编程的基础概念,包括线程的创建与启动,线程的生命周期,以及如何使用`Thread`类和`Runnable`接口。 2. **同步机制**:详述Java中的同步控制方法,如`synchronized`关键字,`...
第7节多种创建线程的方式案例演示(一)带返回值的方式00:17:12分钟 | 第8节多种创建线程的方式案例演示(二)使用线程池00:15:40分钟 | 第9节Spring对并发的支持:Spring的异步任务00:11:10分钟 | 第10节使用jdk...