1. 程式人生 > >子執行緒中的異常捕獲

子執行緒中的異常捕獲

根據java執行緒的本質,當一個執行緒丟擲異常時,在主執行緒中加try catch 是無法捕獲到其丟擲的異常的,如下面程式碼所示:

   private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public
void onClickBtn(View view) { try { Thread thread = new Thread(new ExceptionThread()); ExecutorService service = Executors.newCachedThreadPool(); service.execute(thread); } catch (Exception e) { Log.d(TAG, "onClickBtn: catch the excepiton"
); e.printStackTrace(); } } class ExceptionThread implements Runnable { @Override public void run() { Log.d(TAG, "run: start to throw exception"); throw new RuntimeException(); } }

點選按鈕應用就會crash,異常log如下:

2018-11-12 16:32:08.106 32514-32545/com.air.testexceptioncatchinthead D/MainActivity: run: start to throw exception
    
    --------- beginning of crash
2018-11-12 16:32:08.113 32514-32545/com.air.testexceptioncatchinthead E/AndroidRuntime: FATAL EXCEPTION: pool-1-thread-1
    Process: com.air.testexceptioncatchinthead, PID: 32514
    java.lang.RuntimeException
        at com.air.testexceptioncatchinthead.MainActivity$ExceptionThread.run(MainActivity.java:37)
        at java.lang.Thread.run(Thread.java:764)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:764)

從上面實驗中可以看到,在有多個執行緒時,另外一個執行緒是無法捕獲到另外一個執行緒丟擲的異常的。

那麼這種異常如何捕獲呢,java 在JDK5中引入了UncaughtExceptionHandler介面,實現如下:

class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
        @Override
        public void uncaughtException(Thread t, Throwable e) {
            Log.d(TAG, "uncaughtException: caught " + t + e.toString());
            e.printStackTrace();
        }
    }
public void onClickBtn(View view) {
        Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
        new Thread(new ExceptionThread()).start();
    }

此時點選,就會發現app已經不會crash了,完整程式碼如下:

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void onClickBtn(View view) {
        Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
        new Thread(new ExceptionThread()).start();
    }

    class ExceptionThread implements Runnable {

        @Override
        public void run() {
            Log.d(TAG, "run: start to throw exception");
            throw new NullPointerException();
        }
    }

    class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
        @Override
        public void uncaughtException(Thread t, Throwable e) {
            Log.d(TAG, "uncaughtException: caught " + t + e.toString());
            e.printStackTrace();
        }
    }
} 

注意:JVM設計源於這樣一種理念,執行緒是獨立執行的程式碼片斷,執行緒的問題應該由執行緒自己來解決,而不要委託到外部。基於這樣的理念,在java中執行緒方法的異常都應該線上程內部處理掉,這種外部捕獲異常的方案通常情況下不應該使用