控制被一个执行者拒绝的任务

当要结束一个执行者的执行,您使用 shutdown() 方法告知它应该结束了。执行者等待正在允许或等待运行的任务的完成,然后结束执行。

如果您在 shutdown() 方法和执行者结束执行之间发给执行者一个任务,任务因为执行者不再接受新任务而被拒绝。 ThreadPoolExecutor 提供了一个机制,在一个任务被拒绝时调用。

任务

实现一个 RejectedExecutionHandler 来管理一个执行者中被拒绝的任务。

实现

本节的示例代码在 com.elanzone.books.noteeg.chpt4.sect12 package中

  • RejectedExecutionHandler 接口实现类: RejectedTaskController

    • 覆盖 rejectedExecution 方法: 输出线程及执行者的信息
        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
            System.out.printf("RejectedTaskController: The task %s has been rejected\n", r.toString());
            System.out.printf("RejectedTaskController: %s\n", executor.toString());
            System.out.printf("RejectedTaskController: Terminating: %s\n", executor.isTerminating());
            System.out.printf("RejectedTaskController: Terminated: %s\n", executor.isTerminated());
        }
    
  • 线程类 : Task

    • 属性 name : String 类型,任务名称
        private String name;
    
        public Task(String name) {
            this.name = name;
        }
    
    • run 方法 : 输出相关信息、随机睡上几秒
        @Override
        public void run() {
            System.out.println("Task " + name + ": Starting");
    
            try {
                long duration = (long) (Math.random() * 10);
                System.out.printf("Task %s: ReportGenerator: Generating a report during %d seconds\n", name, duration);
                TimeUnit.SECONDS.sleep(duration);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            System.out.printf("Task %s: Ending\n", name);
        }
    
    • 覆盖 toString() 方法: 返回任务名称
        @Override
        public String toString() {
            return name;
        }
    
  • 控制类 : Main

    • 创建一个 RejectedTaskController 对象
        RejectedTaskController controller = new RejectedTaskController();
    
    • 使用 Executors 类生成一个 ThreadPoolExecutor, 并调用 setRejectedExecutionHandler 设置被拒绝任务的处理器
        ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newCachedThreadPool();
        executor.setRejectedExecutionHandler(controller);
    
    • 创建3个Task对象并提交给 executor 执行
        System.out.printf("Main: Starting.\n");
        for (int i = 0; i < 3; i++) {
            Task task = new Task("Task" + i);
            executor.submit(task);
        }
    
    • 调用 executor 的 shutdown() 方法结束 executor 的执行
        System.out.printf("Main: Shutting down the Executor.\n");
        executor.shutdown();
    
    • 新创建一个任务提交给 executor 执行
        System.out.printf("Main: Sending another Task.\n");
        Task task = new Task("RejectedTask");
        executor.submit(task);
    

工作原理

为了为一个执行者管理被拒绝的任务,要创建一个实现了 RejectedExecutionHandler 接口的类。 此接口有一个名为 rejectedExecution() 的方法,有2个参数:

  • Runnable 对象:被拒绝的任务
  • Executor 对象: 拒绝此任务的执行者

会为每个被执行者拒绝的任务调用此方法。要使用 Executor 类的 setRejectedExecutionHandler() 方法设置被拒绝任务的处理器。

了解更多

当一个执行者收到一个任务执行时,它检查 shutdown() 方法是否已被调用。

  • 如果已被调用,它拒绝此任务
    1. 查找由 setRejectedExecutionHandler() 方法设置的处理器
      • 如果有设置,则调用该处理器的 rejectedExecution() 方法
      • 否则抛出 RejectedExecutionExeption 异常。(这是一个运行时异常,所以语法上不是一定要用catch语句捕捉它)