最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中捕獲線程異常的幾種方式總結

 更新時間:2022年11月24日 15:59:27   作者:潘建南  
這篇文章主要介紹了Java中捕獲線程異常的幾種方式總結,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

首先,我們要知道,在Java中,線程中的異常是不能拋出到調用該線程的外部方法中捕獲的。

為什么不能拋出到外部線程捕獲?

因為線程是獨立執(zhí)行的代碼片斷,線程的問題應該由線程自己來解決,而不要委托到外部。

基于這樣的設計理念,在Java中,線程方法的異常都應該在線程代碼邊界之內(run方法內)進行try catch并處理掉。

換句話說,我們不能捕獲從線程中逃逸的異常。

怎么進行的限制?

通過java.lang.Runnable.run()方法聲明(因為此方法聲明上沒有throw exception部分)進行了約束。

如果在線程中拋出了線程會怎么樣?

線程會立即終結。

現(xiàn)在我們可以怎樣捕獲線程中的異常?

Java中在處理異常的時候,通常的做法是使用try-catch-finally來包含代碼塊,但是Java自身還有一種方式可以處理——使用UncaughtExceptionHandler。

它能檢測出某個線程由于未捕獲的異常而終結的情況。

當一個線程由于未捕獲異常而退出時,JVM會把這個事件報告給應用程序提供的UncaughtExceptionHandler異常處理器(這是Thread類中的接口):

//Thread類中的接口
public interface UncaughtExceptionHanlder {
?? ?void uncaughtException(Thread t, Throwable e);
}

JDK5之后允許我們在每一個Thread對象上添加一個異常處理器UncaughtExceptionHandler 。

Thread.UncaughtExceptionHandler.uncaughtException()方法會在線程因未捕獲的異常而面臨死亡時被調用。

首先要先定義一個異常捕獲器:

public class MyUnchecckedExceptionhandler implements UncaughtExceptionHandler {
? ? @Override
? ? public void uncaughtException(Thread t, Throwable e) {
? ? ? ? System.out.println("捕獲異常處理方法:" + e);
? ? }
}

方法1. 創(chuàng)建線程時設置異常處理Handler

Thread t = new Thread(new ExceptionThread());
t.setUncaughtExceptionHandler(new MyUnchecckedExceptionhandler());
t.start();

方法2. 使用Executors創(chuàng)建線程時,還可以在ThreadFactory中設置

ExecutorService exec = Executors.newCachedThreadPool(new ThreadFactory(){
? ? ? ? ? ? @Override
? ? ? ? ? ? public Thread newThread(Runnable r) {
? ? ? ? ? ? ? ? Thread thread = new Thread(r);
? ? ? ? ? ? ? ? thread.setUncaughtExceptionHandler(new MyUnchecckedExceptionhandler());
? ? ? ? ? ? ? ? return thread;
? ? ? ? ? ? }
});
exec.execute(new ExceptionThread());

不過,上面的結果能證明:通過execute方式提交的任務,能將它拋出的異常交給異常處理器。

如果改成submit方式提交任務,則異常不能被異常處理器捕獲,這是為什么呢?

查看源碼后可以發(fā)現(xiàn),如果一個由submit提交的任務由于拋出了異常而結束,那么這個異常將被Future.get封裝在ExecutionException中重新拋出。

所以,通過submit提交到線程池的任務,無論是拋出的未檢查異常還是已檢查異常,都將被認為是任務返回狀態(tài)的一部分,因此不會交由異常處理器來處理。

java.util.concurrent.FutureTask 源碼

public V get() throws InterruptedException, ExecutionException {
? ? int s = state;
? ? if (s <= COMPLETING)//如果任務沒有結束,則等待結束
? ? ? ? s = awaitDone(false, 0L);
? ? return report(s);//如果執(zhí)行結束,則報告執(zhí)行結果
}

@SuppressWarnings("unchecked")
private V report(int s) throws ExecutionException {
? ? Object x = outcome;
? ? if (s == NORMAL)//如果執(zhí)行正常,則返回結果
? ? ? ? return (V)x;
? ? if (s >= CANCELLED)//如果任務被取消,調用get則報CancellationException
? ? ? ? throw new CancellationException();
? ? throw new ExecutionException((Throwable)x);//執(zhí)行異常,則拋出ExecutionException
}

方法3. 使用線程組ThreadGroup

//1.創(chuàng)建線程組
ThreadGroup threadGroup =
? ? ? ? // 這是匿名類寫法
? ? ? ? new ThreadGroup("group") {
? ? ? ? ? ? // 繼承ThreadGroup并重新定義以下方法
? ? ? ? ? ? // 在線程成員拋出unchecked exception 會執(zhí)行此方法
? ? ? ? ? ? @Override
? ? ? ? ? ? public void uncaughtException(Thread t, Throwable e) {
? ? ? ? ? ? ? ? //4.處理捕獲的線程異常
? ? ? ? ? ? }
? ? ? ? };
//2.創(chuàng)建Thread ? ? ? ?
Thread thread = new Thread(threadGroup, new Runnable() {
? ? @Override
? ? public void run() {
? ? ? ? System.out.println(1 / 0);

? ? }
}, "my_thread"); ?
//3.啟動線程
thread.start(); ??

方法4. 默認的線程異常捕獲器

如果我們只需要一個線程異常處理器處理線程的異常,那么我們可以設置一個默認的線程異常處理器,當線程出現(xiàn)異常時,

如果我們沒有指定線程的異常處理器,而且線程組也沒有設置,那么就會使用默認的線程異常處理器

// 設置默認的線程異常捕獲處理器
Thread.setDefaultUncaughtExceptionHandler(new MyUnchecckedExceptionhandler());

上面說的4種方法都是基于線程異常處理器實現(xiàn)的,接下來將的幾種方法則不需要依賴異常處理器。

方法5. 使用FetureTask來捕獲異常

//1.創(chuàng)建FeatureTask
FutureTask<Integer> futureTask = new FutureTask<>(new Callable<Integer>() {
? ? @Override
? ? public Integer call() throws Exception {
? ? ? ? return 1/0;
? ? }
});
//2.創(chuàng)建Thread
Thread thread = new Thread(futureTask);
//3.啟動線程
thread.start();
try {
? ? Integer result = futureTask.get();
} catch (InterruptedException e) {
? ? e.printStackTrace();
} catch (ExecutionException e) {
? ? //4.處理捕獲的線程異常
}

方法6. 利用線程池提交線程時返回的Feature引用

//1.創(chuàng)建線程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
//2.創(chuàng)建Callable,有返回值的,你也可以創(chuàng)建一個線程實現(xiàn)Callable接口。
// ?如果你不需要返回值,這里也可以創(chuàng)建一個Thread即可,在第3步時submit這個thread。
Callable<Integer> callable = new Callable<Integer>() {
? ? @Override
? ? public Integer call() throws Exception {
? ? ? ? return 1/0;
? ? }
};
//3.提交待執(zhí)行的線程
Future<Integer> future = executorService.submit(callable);
try {
? ? ?Integer result = future.get();
} catch (InterruptedException e) {
? ? e.printStackTrace();
} catch (ExecutionException e) {
? ? //4.處理捕獲的線程異常
}

實現(xiàn)原理可以看一下方法2的說明。

方法6本質上和方法5一樣是基于FutureTask實現(xiàn)的。

方法7. 重寫ThreadPoolExecutor的afterExecute方法

//1.創(chuàng)建線程池
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 10, 0L, TimeUnit.MILLISECONDS,
? ? ? ? new LinkedBlockingQueue<>()) {
? ? @Override
? ? protected void afterExecute(Runnable r, Throwable t) {
? ? ? ? if (r instanceof Thread) {
? ? ? ? ? ? if (t != null) {
? ? ? ? ? ? ? ? //處理捕獲的異常
? ? ? ? ? ? }
? ? ? ? } else if (r instanceof FutureTask) {
? ? ? ? ? ? FutureTask futureTask = (FutureTask) r;
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? futureTask.get();
? ? ? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? } catch (ExecutionException e) {
? ? ? ? ? ? ? ? //處理捕獲的異常
? ? ? ? ? ? }
? ? ? ? }

? ? }
};


Thread t1 = new Thread(() -> {
? ? int c = 1 / 0;
});
threadPoolExecutor.execute(t1);

Callable<Integer> callable = () -> 2 / 0;
threadPoolExecutor.submit(callable);

總結

線程最好交由線程池進行管理。

線程池中如果你的線程不需要返回值則可以使用方法2,利用ThreadFactory為線程指定統(tǒng)一的異常處理器。記得一定要用execute方式提交任務,否則異常處理器捕獲不到異常。

線程池中如果你的線程需要返回值,你又想捕獲線程異常,則需要借助FutureTask,即使用方法6。使用submit方法提交線程。當然了,不需要返回值的情況也可以使用方法6。

方法7同時支持execute和submit提交任務時異常的捕獲,適合相同類型任務的統(tǒng)一異常處理,但是異常處理粒度較粗,而方法2和方法6可以針對每個任務進行自定義的異常處理。

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • java跳出多重循環(huán)的三種實現(xiàn)方式

    java跳出多重循環(huán)的三種實現(xiàn)方式

    文章主要介紹了Java中跳出多重循環(huán)的三種方式:使用`break`配合標簽、在布爾表達式中添加判斷變量、以及使用`try-catch`制造異常,每種方式都有具體的代碼示例,并輸出了相應的執(zhí)行結果
    2025-01-01
  • Java使用Optional實現(xiàn)優(yōu)雅避免空指針異常

    Java使用Optional實現(xiàn)優(yōu)雅避免空指針異常

    空指針異常(NullPointerException)可以說是Java程序員最容易遇到的問題了。為了解決這個問題,Java?8?版本中推出了?Optional?類,本文就來講講如何使用Optional實現(xiàn)優(yōu)雅避免空指針異常吧
    2023-03-03
  • Spring Boot啟動過程(五)之Springboot內嵌Tomcat對象的start教程詳解

    Spring Boot啟動過程(五)之Springboot內嵌Tomcat對象的start教程詳解

    這篇文章主要介紹了Spring Boot啟動過程(五)之Springboot內嵌Tomcat對象的start的相關資料,需要的朋友可以參考下
    2017-04-04
  • java 如何給對象中的包裝類設置默認值

    java 如何給對象中的包裝類設置默認值

    這篇文章主要介紹了java 如何給對象中的包裝類設置默認值,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Java Bigdecimal使用原理詳解

    Java Bigdecimal使用原理詳解

    這篇文章主要介紹了Java Bigdecimal使用原理詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-03-03
  • idea聚合工程搭建過程詳解

    idea聚合工程搭建過程詳解

    本章主要以order訂單服務來遠程調用payment支付服務為例,當然這里只是簡單的一個遠程調用,沒有太復雜的邏輯,重點是要掌握的是maven的聚合工程搭建,微服務分模塊的思想,每一個步驟我都會詳細記錄,并且文章下方還提供了git源碼地址
    2022-06-06
  • Java如何向主函數(shù)main中傳入參數(shù)

    Java如何向主函數(shù)main中傳入參數(shù)

    這篇文章主要介紹了Java如何向主函數(shù)main中傳入參數(shù),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • 淺析springcloud 整合 zipkin-server 內存日志監(jiān)控

    淺析springcloud 整合 zipkin-server 內存日志監(jiān)控

    Zipkin是一款開源的分布式實時數(shù)據(jù)追蹤系統(tǒng)(Distributed Tracking System),其主要功能是聚集來自各個異構系統(tǒng)的實時監(jiān)控數(shù)據(jù)。這篇文章主要介紹了springcloud 整合 zipkin-server 內存日志監(jiān)控,需要的朋友可以參考下
    2019-11-11
  • Java方法反射實現(xiàn)原理詳解

    Java方法反射實現(xiàn)原理詳解

    這篇文章主要為大家詳細介紹了Java方法反射的實現(xiàn)原理,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-10-10
  • java微信企業(yè)號開發(fā)之通訊錄

    java微信企業(yè)號開發(fā)之通訊錄

    這篇文章主要為大家詳細介紹了java微信企業(yè)號開發(fā)之通訊錄的相關資料,感興趣的小伙伴們可以參考一下
    2016-06-06

最新評論

平凉市| 波密县| 云安县| 巫溪县| 呼和浩特市| 西安市| 舒城县| 广昌县| 淮北市| 秀山| 天台县| 浦江县| 读书| 宣城市| 隆子县| 武乡县| 微山县| 临洮县| 建宁县| 太白县| 中山市| 金平| 江安县| 莱西市| 会东县| 公主岭市| 古丈县| 水富县| 阳新县| 南丰县| 隆安县| 堆龙德庆县| 新民市| 顺昌县| 安乡县| 贵州省| 东海县| 宜良县| 峨眉山市| 鹰潭市| 昌邑市|