覆盖ThreadPoolExecutor afterExecute方法 - 任何缺点?

时间:2016-02-12 15:16:02

标签: java multithreading threadpoolexecutor

钩子方法的优点:

beforeExecute(Thread, Runnable) afterExecute(Runnable, Throwable)

  在执行每项任务之前和之后调用的

beforeExecute(Thread, Runnable)和afterExecute(Runnable, Throwable)方法。这些可以用来操纵执行环境;例如,重新初始化ThreadLocals,收集统计信息或添加日志条目

我正在使用自定义ThreadPoolExecutor来处理未捕获的异常。我可以在try{} catch{}Runnable中添加Callable块,但假设您无法强制开发人员在相关的Runnable和Callable任务中添加这些块。

CustomThreadPoolExecutor覆盖afterExecute中的ThreadPoolExecutor()方法,如下所示(我已将变量b值指定为零以模拟算术异常。

import java.util.concurrent.*;
import java.util.*;

class CustomThreadPoolExecutor extends ThreadPoolExecutor {

   public CustomThreadPoolExecutor() { 
       super(1,10,60,TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(1000));
   }

   protected void afterExecute(Runnable r, Throwable t) {
     super.afterExecute(r, t);
     if (t == null && r instanceof Future<?>) {
       try {
         Object result = ((Future<?>) r).get();
         System.out.println(result);
       } catch (CancellationException ce) {
           t = ce;
       } catch (ExecutionException ee) {
           t = ee.getCause();
       } catch (InterruptedException ie) {
           Thread.currentThread().interrupt(); // ignore/reset
       }
     }
     if (t != null)
       t.printStackTrace();
   }
 }


public class CustomThreadPoolExecutorDemo{

    public static void main(String args[]){
        System.out.println("creating service");
        //ExecutorService service = Executors.newFixedThreadPool(10);
        CustomThreadPoolExecutor service = new CustomThreadPoolExecutor();
        service.submit(new Runnable(){
                 public void run(){
                    int a=4, b = 0;
                    System.out.println("a and b="+a+":"+b);
                    System.out.println("a/b:"+(a/b));
                    System.out.println("Thread Name in Runnable after divide by zero:"+Thread.currentThread().getName());
                 }
            });
        service.shutdown();
    }
}

由于submit()隐藏了框架中的异常,因此我重写了afterExecute()方法来捕获异常。

在此方法中,我使用以下语句添加了阻塞调用

 Object result = ((Future<?>) r).get();

目前我有10个队列容量为1000的线程。假设我的Runnable需要5秒才能完成。

通过覆盖afterExecute()方法,我是否会产生任何性能开销或使用此方法的任何缺点?

2 个答案:

答案 0 :(得分:1)

更好的解决方案,坚持从submit()返回的Future,然后您可以在主线程中处理异常,而不是黑客执行程序为您打印出来。

另一种选择是使用一个公共基础Runnable来实现你想要的异常处理,例如:

public abstract class BaseRunnable implements Runnable {
  public final run() {
    try {
      runImpl();
    } catch(Throwable t) {
      t.printStackTrace();
    }
  }
  protected abstract runImpl() throws Exception;
}

答案 1 :(得分:1)

不,你的阻止调用不会带来开销,因为任务已经完成执行并且status >= NORMAL正如您在void runWorker(Worker w)

中看到的那样
beforeExecute(wt, task);
Throwable thrown = null;
try {
    task.run();
} catch (RuntimeException x) {
    thrown = x; throw x;
} catch (Error x) {
    thrown = x; throw x;
} catch (Throwable x) {
    thrown = x; throw new Error(x);
} finally {
    afterExecute(task, thrown);
}