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。