1. 程式人生 > >多執行緒異常捕獲問題:棄用Thread,改用FutureTask,附測試結果

多執行緒異常捕獲問題:棄用Thread,改用FutureTask,附測試結果

 Thread的在其他執行緒裡丟擲的異常在當前執行緒處理不到,還是要用執行緒池或設定UncaughtExceptionHandler才能處理到。然而FutureTask就可以直接在另一個執行緒捕獲到並處理。
 這樣Thread在實際應用中會導致丟擲了未知異常沒被處理,也沒報錯,導致當前執行緒呼叫方法得到的預期之外的結果。 
 原因之一可能是這樣,java多執行緒是伴隨著java出生就有的,java是天生的多執行緒語言,最開始的某些考慮可能並不全面。而併發包是jdk1.5之後才出現的,FutureTask本身其實實現了Runnable介面,定製化了,還有別的一些併發包類基本上全部是由一個java併發程式設計的大師實現的,都是jdk1.5之後的產物。

下面是測試程式碼:

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());
        }
    }
}
試了下,Thread的setUncaughtExceptionHandler方法也是不可靠的,有時可以,但經常捕獲不到。而且另起Thread執行緒中即使使用了try-catch塊,也是不可靠的,依舊只是有時能捕獲到,經常是捕獲不到的,沒捕獲的異常也不一定會在控制檯輸出。感覺這個類真要廢棄了。而FutureTask目前沒發現有這樣的問題。