重写 ThreadPoolExecutor afterExecute 方法 - 有什么缺点吗?
Overriding ThreadPoolExecutor afterExecute method - any cons?
钩子方法的优点:
beforeExecute(Thread, Runnable)
和 afterExecute(Runnable, Throwable)
beforeExecute(Thread, Runnable
) and afterExecute(Runnable, Throwable)
methods that are called before and after execution of each task. These can be used to manipulate the execution environment; for example, reinitializing ThreadLocals, gathering statistics, or adding log entries
我正在使用自定义 ThreadPoolExecutor
来处理未捕获的异常。我可以在 Runnable
和 Callable
中添加 try{} catch{}
块,但假设您不能强制开发人员在相关的 Runnable
和 Callable 任务中添加这些块。
此 CustomThreadPoolExecutor
覆盖 ThreadPoolExecutor
中的 afterExecute
() 方法,如下所示(我已将变量 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
() 方法,我是否会产生任何性能开销或使用这种方法的任何缺点?
更好的解决方案,保留从 submit()
返回的 Future,然后您可以在主线程中处理异常,而不是黑掉执行程序来为您打印出来。
另一种选择是使用一个通用的 Runnable 基类,它实现了您想要的异常处理,例如:
public abstract class BaseRunnable implements Runnable {
public final run() {
try {
runImpl();
} catch(Throwable t) {
t.printStackTrace();
}
}
protected abstract runImpl() throws Exception;
}
不,您的阻塞调用不会带来开销,因为任务已经完成执行并且具有 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);
}
钩子方法的优点:
beforeExecute(Thread, Runnable)
和 afterExecute(Runnable, Throwable)
beforeExecute(Thread, Runnable
) andafterExecute(Runnable, Throwable)
methods that are called before and after execution of each task. These can be used to manipulate the execution environment; for example, reinitializing ThreadLocals, gathering statistics, or adding log entries
我正在使用自定义 ThreadPoolExecutor
来处理未捕获的异常。我可以在 Runnable
和 Callable
中添加 try{} catch{}
块,但假设您不能强制开发人员在相关的 Runnable
和 Callable 任务中添加这些块。
此 CustomThreadPoolExecutor
覆盖 ThreadPoolExecutor
中的 afterExecute
() 方法,如下所示(我已将变量 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
() 方法,我是否会产生任何性能开销或使用这种方法的任何缺点?
更好的解决方案,保留从 submit()
返回的 Future,然后您可以在主线程中处理异常,而不是黑掉执行程序来为您打印出来。
另一种选择是使用一个通用的 Runnable 基类,它实现了您想要的异常处理,例如:
public abstract class BaseRunnable implements Runnable {
public final run() {
try {
runImpl();
} catch(Throwable t) {
t.printStackTrace();
}
}
protected abstract runImpl() throws Exception;
}
不,您的阻塞调用不会带来开销,因为任务已经完成执行并且具有 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);
}