submit() vs execute() 异常处理差异
通常,execute()
命令用于 fire 和 forget 调用(不需要分析结果),submit()
命令用于分析 Future 对象的结果。
我们应该知道这两个命令之间的异常处理机制的关键区别。
如果你没有捕获它们,框架就会吞下来自 submit()
的异常。
代码示例了解差异:
情况 1:使用 execute()
命令提交 Runnable,该命令报告异常
import java.util.concurrent.*;
import java.util.*;
public class ExecuteSubmitDemo {
public ExecuteSubmitDemo() {
System.out.println("creating service");
ExecutorService service = Executors.newFixedThreadPool(2);
//ExtendedExecutor service = new ExtendedExecutor();
for (int i = 0; i < 2; i++){
service.execute(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();
}
public static void main(String args[]){
ExecuteSubmitDemo demo = new ExecuteSubmitDemo();
}
}
class ExtendedExecutor extends ThreadPoolExecutor {
public ExtendedExecutor() {
super(1, 1, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(100));
}
// ...
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
if (t == null && r instanceof Future<?>) {
try {
Object result = ((Future<?>) r).get();
} catch (CancellationException ce) {
t = ce;
} catch (ExecutionException ee) {
t = ee.getCause();
} catch (InterruptedException ie) {
Thread.currentThread().interrupt(); // ignore/reset
}
}
if (t != null)
System.out.println(t);
}
}
输出:
creating service
a and b=4:0
a and b=4:0
Exception in thread "pool-1-thread-1" Exception in thread "pool-1-thread-2" java.lang.ArithmeticException: / by zero
at ExecuteSubmitDemo$1.run(ExecuteSubmitDemo.java:15)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
java.lang.ArithmeticException: / by zero
at ExecuteSubmitDemo$1.run(ExecuteSubmitDemo.java:15)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
情况 2:用 submit()
替换 execute()
: service.submit(new
Runnable(){
在这种情况下,框架吞下了异常,因为 run()
方法没有明确地捕获它们。
输出:
creating service
a and b=4:0
a and b=4:0
案例 3:将 newFixedThreadPool 更改为 ExtendedExecutor
//ExecutorService service = Executors.newFixedThreadPool(2);
ExtendedExecutor service = new ExtendedExecutor();
输出:
creating service
a and b=4:0
java.lang.ArithmeticException: / by zero
a and b=4:0
java.lang.ArithmeticException: / by zero
我已经演示了这个示例以涵盖两个主题:使用自定义 ThreadPoolExecutor 并使用自定义 ThreadPoolExecutor 处理 Exectpion。
针对上述问题的其他简单解决方案: 当你使用普通的 ExecutorService&submit 命令时,从 Future()
命令获取 Future 对象,调用 Future 上的 get()
API。捕获已在 afterExecute 方法实现中引用的三个异常。自定义 ThreadPoolExecutor 优于此方法:你必须只在一个地方处理异常处理机制 - 自定义 ThreadPoolExecutor。