线程执行者(十二)执行者控制被拒绝的任务

简介:

执行者控制被拒绝的任务

当你想要结束执行者的执行,你使用shutdown()方法来表明它的结束。执行者等待正在运行或等待它的执行的任务的结束,然后结束它们的执行。

如果你在shutdown()方法和执行者结束之间,提交任务给执行者,这个任务将被拒绝,因为执行者不再接收新的任务。ThreadPoolExecutor类提供一种机制,在调用shutdown()后,不接受新的任务。

在这个指南中,你将学习如何通过实现RejectedExecutionHandler,在执行者中管理拒绝任务。

准备工作…

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

如何做…

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

1.创建RejectedTaskController类,实现RejectedExecutionHandler接口。实现这个接口的rejectedExecution()方法。写入被拒绝任务的名称和执行者的名称与状态到控制台。


1 public class RejectedTaskController implements
2 RejectedExecutionHandler {
3 @Override
4 public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
5 System.out.printf("RejectedTaskController: The task %s has been rejected\n",r.toString());
6 System.out.printf("RejectedTaskController: %s\n",executor.toString());
7 System.out.printf("RejectedTaskController: Terminating:%s\n",executor.isTerminating());
8 System.out.printf("RejectedTaksController: Terminated:%s\n",executor.isTerminated());
9 }

2.实现Task类,实现Runnable接口。


1 public class Task implements Runnable{

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


1 private String name;

4.实现这个类的构造器,初始化这个类的属性。


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

5.实现run()方法,写入信息到控制台,表明这个方法开始执行。


1 @Override
2 public void run() {
3 System.out.println("Task "+name+": Starting");

6.等待一段随机时间。


1 try {
2 long duration=(long)(Math.random()*10);
3 System.out.printf("Task %s: ReportGenerator: Generating a report during %d seconds\n",name,duration);
4 TimeUnit.SECONDS.sleep(duration);
5 } catch (InterruptedException e) {
6 e.printStackTrace();
7 }

7.写入信息到控制台,表明方法的结束。


1 System.out.printf("Task %s: Ending\n",name);
2 }

8.重写toString()方法,返回任务的名称。


1 public String toString() {
2 return name;
3 }

9.实现这个示例的主类,通过创建Main类,并实现main()方法。


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

10.创建一个RejectedTaskController对象,管理拒绝的任务。


1 RejectecTaskController controller=new RejectecTaskController();

11.使用Executors类的newCachedThreadPool()方法,创建ThreadPoolExecutor。


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

12.建立执行者的拒绝任务控制器。


1 executor.setRejectedExecutionHandler(controller);

13.创建任务并提交它们给执行者。


1 System.out.printf("Main: Starting.\n");
2 for (int i=0; i<3; i++) {
3 Task task=new Task("Task"+i);
4 executor.submit(task);
5 }

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


1 System.out.printf("Main: Shutting down the Executor.\n");
2 executor.shutdown();

15.创建其他任务并提交给执行者。


1 System.out.printf("Main: Sending another Task.\n");
2 Task task=new Task("RejectedTask");
3 executor.submit(task);

16.写入信息到控制台,表明程序结束。


1 System.out.println("Main: End");
2 System.out.printf("Main: End.\n");

这是如何工作的…

以下截图显示示例的执行结果:

8

你可以看出当执行者关闭时,任务被拒绝提交。RejectecTaskController将有关于任务和执行者的信息写入到控制台。

为了管理执行者控制拒绝任务,你应该实现RejectedExecutionHandler接口。该接口有带有两个参数的方法rejectedExecution():

  • Runnable对象,存储被拒绝的任务
  • Executor对象,存储拒绝任务的执行者

每个被执行者拒绝的任务都会调用这个方法。你必须使用Executor类的setRejectedExecutionHandler()方法设置拒绝任务的处理器。

不止这些…

当执行者接收任务时,会检查shutdown()是否已经被调用了。如果被调用了,它拒绝这个任务。首先,它查找 setRejectedExecutionHandler()设置的处理器。如果有一个(处理器),它调用那个类的 rejectedExecution()方法,否则,它将抛RejectedExecutionExeption异常。这是一个运行时异常,所以你不需要 用catch语句来控制它。

参见

  • 在第4章,线程执行者中的创建一个线程执行者指南
目录
相关文章
|
1月前
|
缓存 负载均衡 Java
c++写高性能的任务流线程池(万字详解!)
本文介绍了一种高性能的任务流线程池设计,涵盖多种优化机制。首先介绍了Work Steal机制,通过任务偷窃提高资源利用率。接着讨论了优先级任务,使不同优先级的任务得到合理调度。然后提出了缓存机制,通过环形缓存队列提升程序负载能力。Local Thread机制则通过预先创建线程减少创建和销毁线程的开销。Lock Free机制进一步减少了锁的竞争。容量动态调整机制根据任务负载动态调整线程数量。批量处理机制提高了任务处理效率。此外,还介绍了负载均衡、避免等待、预测优化、减少复制等策略。最后,任务组的设计便于管理和复用多任务。整体设计旨在提升线程池的性能和稳定性。
79 5
|
3月前
|
前端开发 JavaScript 大数据
React与Web Workers:开启前端多线程时代的钥匙——深入探索计算密集型任务的优化策略与最佳实践
【8月更文挑战第31天】随着Web应用复杂性的提升,单线程JavaScript已难以胜任高计算量任务。Web Workers通过多线程编程解决了这一问题,使耗时任务独立运行而不阻塞主线程。结合React的组件化与虚拟DOM优势,可将大数据处理等任务交由Web Workers完成,确保UI流畅。最佳实践包括定义清晰接口、加强错误处理及合理评估任务特性。这一结合不仅提升了用户体验,更为前端开发带来多线程时代的全新可能。
81 1
|
3月前
|
存储 监控 Java
|
4月前
|
Java Linux
Java演进问题之1:1线程模型对于I/O密集型任务如何解决
Java演进问题之1:1线程模型对于I/O密集型任务如何解决
|
3月前
|
Cloud Native Java 调度
项目环境测试问题之线程同步器会造成执行完任务的worker等待的情况如何解决
项目环境测试问题之线程同步器会造成执行完任务的worker等待的情况如何解决
|
3月前
|
Java 测试技术 PHP
父子任务使用不当线程池死锁怎么解决?
在Java多线程编程中,线程池有助于提升性能与资源利用效率,但若父子任务共用同一池,则可能诱发死锁。本文通过一个具体案例剖析此问题:在一个固定大小为2的线程池中,父任务直接调用`outerTask`,而`outerTask`再次使用同一线程池异步调用`innerTask`。理论上,任务应迅速完成,但实际上却超时未完成。经由`jstack`输出的线程调用栈分析发现,线程陷入等待状态,形成“死锁”。原因是子任务需待父任务完成,而父任务则需等待子任务执行完毕以释放线程,从而相互阻塞。此问题在测试环境中不易显现,常在生产环境下高并发时爆发,重启或扩容仅能暂时缓解。
|
4月前
|
安全
线程操纵术并行策略问题之ForkJoinTask提交任务的问题如何解决
线程操纵术并行策略问题之ForkJoinTask提交任务的问题如何解决
|
4月前
线程操纵术并行策略问题之ForkJoinTask提交任务的问题如何解决
线程操纵术并行策略问题之ForkJoinTask提交任务的问题如何解决
|
4月前
|
并行计算 安全 Java
线程操纵术并行策略问题之任务执行器(Executor)问题如何解决
线程操纵术并行策略问题之任务执行器(Executor)问题如何解决
|
4月前
|
设计模式 安全 Java
Java面试题:如何实现一个线程安全的单例模式,并确保其在高并发环境下的内存管理效率?如何使用CyclicBarrier来实现一个多阶段的数据处理任务,确保所有阶段的数据一致性?
Java面试题:如何实现一个线程安全的单例模式,并确保其在高并发环境下的内存管理效率?如何使用CyclicBarrier来实现一个多阶段的数据处理任务,确保所有阶段的数据一致性?
65 0