多執行緒異常捕獲問題:棄用Thread,改用FutureTask,附測試結果
阿新 • • 發佈:2019-01-02
Thread的在其他執行緒裡丟擲的異常在當前執行緒處理不到,還是要用執行緒池或設定UncaughtExceptionHandler才能處理到。然而FutureTask就可以直接在另一個執行緒捕獲到並處理。
這樣Thread在實際應用中會導致丟擲了未知異常沒被處理,也沒報錯,導致當前執行緒呼叫方法得到的預期之外的結果。
原因之一可能是這樣,java多執行緒是伴隨著java出生就有的,java是天生的多執行緒語言,最開始的某些考慮可能並不全面。而併發包是jdk1.5之後才出現的,FutureTask本身其實實現了Runnable介面,定製化了,還有別的一些併發包類基本上全部是由一個java併發程式設計的大師實現的,都是jdk1.5之後的產物。
這樣Thread在實際應用中會導致丟擲了未知異常沒被處理,也沒報錯,導致當前執行緒呼叫方法得到的預期之外的結果。
原因之一可能是這樣,java多執行緒是伴隨著java出生就有的,java是天生的多執行緒語言,最開始的某些考慮可能並不全面。而併發包是jdk1.5之後才出現的,FutureTask本身其實實現了Runnable介面,定製化了,還有別的一些併發包類基本上全部是由一個java併發程式設計的大師實現的,都是jdk1.5之後的產物。
下面是測試程式碼:
試了下,Thread的setUncaughtExceptionHandler方法也是不可靠的,有時可以,但經常捕獲不到。而且另起Thread執行緒中即使使用了try-catch塊,也是不可靠的,依舊只是有時能捕獲到,經常是捕獲不到的,沒捕獲的異常也不一定會在控制檯輸出。感覺這個類真要廢棄了。而FutureTask目前沒發現有這樣的問題。package test.exception; import org.junit.Test; import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; /** * Created by jackie on 2017/3/4. * 測試多執行緒捕獲異常 */ public class AnotherThreadExceptionTest { @Test public void testFutureTask() { try { FutureTask task = new FutureTask(new Callable<String>() { @Override public String call() { System.out.println("aaa"); String s ="aaa"; s.equals("ll"); s.substring(5); return s; } }); task.run(); System.out.println("out: "+task.get()); }catch (Exception e ){ e.printStackTrace();//試試註釋掉這行 } } // @Test public void testThread(){ Runnable run = new Runnable() { @Override public void run() { System.out.println("begin..."); String s =null; s.equals("ll"); //這裡空指標異常有時會在控制檯列印,有時不會 try{ "aaa".substring(5); }catch (Exception e){ System.out.println("執行緒內捕獲到異常");//有時甚至只執行這句,不執行下一句 e.printStackTrace();//這裡異常也是有時能捕獲,有時捕獲不到 //// throw new MyException("gg");//java執行緒類中不允許丟擲自定義非執行時異常而不捕獲 //// throw new RuntimeException();//執行時異常可以不捕獲 } } }; try { Thread t = new Thread(run,"thread-001"); //雖然可以設定捕獲未捕獲異常,然而經常捕獲不到 t.setUncaughtExceptionHandler(new MyExceptionHandler()); t.start(); }catch (Exception e){ e.printStackTrace();//這裡經常捕獲不到異常 } } class MyException extends Exception{ public MyException(String message) { super(message); } } class MyExceptionHandler implements Thread.UncaughtExceptionHandler { @Override public void uncaughtException(Thread t, Throwable e) { System.out.println(t.getName()+":"+e.toString()); } } }