线程执行者(十)执行者控制一个任务完成

简介:

执行者控制一个任务完成

FutureTask类提供一个done()方法,允许你在执行者执行任务完成后执行一些代码。你可以用来做一些后处理操作,生成一个报告,通过e-mail发送结果,或释放一些资源。当执行的任务由FutureTask来控制完成,FutureTask会内部调用这个方法。这个方法在任务的结果设置和它的状态变成isDone状态之后被调用,不管任务是否已经被取消或正常完成。

默认情况下,这个方法是空的。你可以重写FutureTask类实现这个方法来改变这种行为。在这个指南中,你将学习如何重写这个方法,在任务完成之后执行代码。

准备工作…

这个指南的例子使用Eclipse IDE实现。如果你使用Eclipse或其他IDE,如NetBeans,打开它并创建一个新的Java项目。

如何做…

按以下步骤来实现的这个例子:

1.创建ExecutableTask类,并指定其实现Callable接口,参数化为String类型。


1 public class ExecutableTask implements Callable<String> {

2.声明一个私有的、类型为String、名为name的属性,用来存储任务的名称。实现getName()方法,返回这个属性值。


1 private String name;
2 public String getName(){
3 return name;
4 }

3.实现这个类的构造器,初始化任务的名称。


1 public ExecutableTask(String name){
2 this.name=name;
3 }

4.实现call()方法。使这个任务睡眠一个随机时间,返回任务名称的信息。


01 @Override
02 public String call() throws Exception {
03 try {
04 long duration=(long)(Math.random()*10);
05 System.out.printf("%s: Waiting %d seconds for results.\
06 n",this.name,duration);
07 TimeUnit.SECONDS.sleep(duration);
08 } catch (InterruptedException e) {
09 }
10 return "Hello, world. I'm "+name;
11 }

5.实现ResultTask类,继承FutureTask类,参数化为String类型。


1 public class ResultTask extends FutureTask<String> {

6.声明一个私有的、类型为String、名为name的属性,用来存储任务的名称。


1 private String name;

7.实现这个类的构造器。它接收一个Callable对象参数。调用父类构造器,使用接收到的任务的属性初始化name属性。


1 public ResultTask(Callable<String> callable) {
2 super(callable);
3 this.name=((ExecutableTask)callable).getName();
4 }

8.重写done()方法。检查isCancelled()方法返回值,并根据这个返回值的不同,写入不同的信息到控制台。


1 @Override
2 protected void done() {
3 if (isCancelled()) {
4 System.out.printf("%s: Has been canceled\n",name);
5 } else {
6 System.out.printf("%s: Has finished\n",name);
7 }
8 }

9.实现示例的主类,创建Main类,实现main()方法。


1 public class Main {
2 public static void main(String[] args) {

10.使用Executors类的newCachedThreadPool()方法创建ExecutorService。


1 ExecutorService executor=(ExecutorService)Executors.newCachedThreadPool();

11.创建存储5个ResultTask对象的一个数组。


1 ResultTask resultTasks[]=new ResultTask[5];

12.初始化ResultTask对象。对于数据的每个位置,首先,你必须创建ExecutorTask,然后,ResultTask使用这个对象,然后,然后submit()方法提交ResultTask给执行者。


1 for (int i=0; i<5; i++) {
2 ExecutableTask executableTask=new ExecutableTask("Task "+i);
3 resultTasks[i]=new ResultTask(executableTask);
4 executor.submit(resultTasks[i]);
5 }

13.令主线程睡眠5秒。


1 try {
2 TimeUnit.SECONDS.sleep(5);
3 } catch (InterruptedException e1) {
4 e1.printStackTrace();
5 }

14.取消你提交给执行者的所有任务。


1 for (int i=0; i<resultTasks.length; i++) {
2 resultTasks[i].cancel(true);
3 }

15.将没有被使用ResultTask对象的get()方法取消的任务的结果写入到控制台。


01 for (int i=0; i<resultTasks.length; i++) {
02 try {
03 if (!resultTasks[i].isCanceled()){
04 System.out.printf("%s\n",resultTasks[i].get());
05 }
06 } catch (InterruptedException | ExecutionException e) {
07 e.printStackTrace();
08 }
09  
10 }

16.使用shutdown()方法关闭执行者。


1 executor.shutdown();
2 }
3 }

它是如何工作的…

当控制任务执行完成后,FutureTask类调用done()方法。在这个示例中,你已经实现一个Callable对象,ExecutableTask类,然后一个FutureTask类的子类用来控制ExecutableTask对象的执行。

在建立返回值和改变任务的状态为isDone状态后,done()方法被FutureTask类内部调用。你不能改变任务的结果值和它的状态,但你可以关闭任务使用的资源,写日志消息,或发送通知。

参见

  • 在第4章,线程执行者中的执行者执行返回结果的任务指南
目录
相关文章
|
存储 Java 数据库
如何处理线程池关闭时未完成的任务?
总之,处理线程池关闭时未完成的任务需要综合考虑多种因素,并根据实际情况选择合适的处理方式。通过合理的处理,可以最大程度地减少任务丢失和数据不一致等问题,确保系统的稳定运行和业务的顺利开展。
538 64
|
消息中间件 监控 Java
线程池关闭时未完成的任务如何保证数据的一致性?
保证线程池关闭时未完成任务的数据一致性需要综合运用多种方法和机制。通过备份与恢复、事务管理、任务状态记录与恢复、数据同步与协调、错误处理与补偿、监控与预警等手段的结合,以及结合具体业务场景进行分析和制定策略,能够最大程度地确保数据的一致性,保障系统的稳定运行和业务的顺利开展。同时,不断地优化和改进这些方法和机制,也是提高系统性能和可靠性的重要途径。
314 62
|
10月前
|
监控 Java
java异步判断线程池所有任务是否执行完
通过上述步骤,您可以在Java中实现异步判断线程池所有任务是否执行完毕。这种方法使用了 `CompletionService`来监控任务的完成情况,并通过一个独立线程异步检查所有任务的执行状态。这种设计不仅简洁高效,还能确保在大量任务处理时程序的稳定性和可维护性。希望本文能为您的开发工作提供实用的指导和帮助。
386 17
|
9月前
|
数据采集 Java 数据处理
Python实用技巧:轻松驾驭多线程与多进程,加速任务执行
在Python编程中,多线程和多进程是提升程序效率的关键工具。多线程适用于I/O密集型任务,如文件读写、网络请求;多进程则适合CPU密集型任务,如科学计算、图像处理。本文详细介绍这两种并发编程方式的基本用法及应用场景,并通过实例代码展示如何使用threading、multiprocessing模块及线程池、进程池来优化程序性能。结合实际案例,帮助读者掌握并发编程技巧,提高程序执行速度和资源利用率。
460 0
|
12月前
|
缓存 监控 Java
Java线程池提交任务流程底层源码与源码解析
【11月更文挑战第30天】嘿,各位技术爱好者们,今天咱们来聊聊Java线程池提交任务的底层源码与源码解析。作为一个资深的Java开发者,我相信你一定对线程池并不陌生。线程池作为并发编程中的一大利器,其重要性不言而喻。今天,我将以对话的方式,带你一步步深入线程池的奥秘,从概述到功能点,再到背景和业务点,最后到底层原理和示例,让你对线程池有一个全新的认识。
245 12
|
缓存 负载均衡 Java
c++写高性能的任务流线程池(万字详解!)
本文介绍了一种高性能的任务流线程池设计,涵盖多种优化机制。首先介绍了Work Steal机制,通过任务偷窃提高资源利用率。接着讨论了优先级任务,使不同优先级的任务得到合理调度。然后提出了缓存机制,通过环形缓存队列提升程序负载能力。Local Thread机制则通过预先创建线程减少创建和销毁线程的开销。Lock Free机制进一步减少了锁的竞争。容量动态调整机制根据任务负载动态调整线程数量。批量处理机制提高了任务处理效率。此外,还介绍了负载均衡、避免等待、预测优化、减少复制等策略。最后,任务组的设计便于管理和复用多任务。整体设计旨在提升线程池的性能和稳定性。
307 5
|
前端开发 JavaScript 大数据
React与Web Workers:开启前端多线程时代的钥匙——深入探索计算密集型任务的优化策略与最佳实践
【8月更文挑战第31天】随着Web应用复杂性的提升,单线程JavaScript已难以胜任高计算量任务。Web Workers通过多线程编程解决了这一问题,使耗时任务独立运行而不阻塞主线程。结合React的组件化与虚拟DOM优势,可将大数据处理等任务交由Web Workers完成,确保UI流畅。最佳实践包括定义清晰接口、加强错误处理及合理评估任务特性。这一结合不仅提升了用户体验,更为前端开发带来多线程时代的全新可能。
419 1
|
存储 监控 Java
|
Cloud Native Java 调度
项目环境测试问题之线程同步器会造成执行完任务的worker等待的情况如何解决
项目环境测试问题之线程同步器会造成执行完任务的worker等待的情况如何解决
115 0
|
Java 测试技术 PHP
父子任务使用不当线程池死锁怎么解决?
在Java多线程编程中,线程池有助于提升性能与资源利用效率,但若父子任务共用同一池,则可能诱发死锁。本文通过一个具体案例剖析此问题:在一个固定大小为2的线程池中,父任务直接调用`outerTask`,而`outerTask`再次使用同一线程池异步调用`innerTask`。理论上,任务应迅速完成,但实际上却超时未完成。经由`jstack`输出的线程调用栈分析发现,线程陷入等待状态,形成“死锁”。原因是子任务需待父任务完成,而父任务则需等待子任务执行完毕以释放线程,从而相互阻塞。此问题在测试环境中不易显现,常在生产环境下高并发时爆发,重启或扩容仅能暂时缓解。
278 0

热门文章

最新文章

下一篇
oss云网关配置