子執行緒中的異常捕獲
阿新 • • 發佈:2019-01-27
根據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中執行緒方法的異常都應該線上程內部處理掉,這種外部捕獲異常的方案通常情況下不應該使用