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

在自定義線程池中捕獲和處理異常實(shí)現(xiàn)過程

 更新時間:2026年05月14日 09:59:13   作者:北執(zhí)南念  
這篇文章主要介紹了在自定義線程池中捕獲和處理異常實(shí)現(xiàn)過程,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

1. MyUncaughtExceptionHandler 類

這是一個自定義的未捕獲異常處理器,當(dāng)線程因?yàn)槲床东@異常而終止時,就會調(diào)用這個處理器。它會記錄錯誤日志,并且可以添加像通知開發(fā)人員等額外的處理邏輯。

package com.hy.archive.config;

import lombok.extern.slf4j.Slf4j;

/**
 * Description: 自定義處理器
 *  這是一個自定義的未捕獲異常處理器,當(dāng)線程因?yàn)槲床东@異常而終止時,就會調(diào)用這個處理器。
 *
 * @Author Js
 * @Create 2025-07-08 20:04
 * @Version 1.0
 */
@Slf4j
public class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        log.error("Exception in thread :" + e);
        // do something
        //記錄日志、告警企業(yè)微信釘釘通知開發(fā)
    }
}

使用說明:一般不會直接調(diào)用這個類,而是通過線程工廠自動設(shè)置到線程上。

2. MyThreadFactory 類

這是一個自定義的線程工廠,其作用是對原生線程工廠進(jìn)行包裝。它會為每個新創(chuàng)建的線程設(shè)置一個自定義的未捕獲異常處理器,也就是MyUncaughtExceptionHandler。

package com.hy.archive.config;

import java.util.concurrent.ThreadFactory;

/**
 * Description: 自定義線程工廠處理
 *
 * @Author Js
 * @Create 2025-07-08 20:01
 * @Version 1.0
 */
public class MyThreadFactory implements ThreadFactory {

    private final ThreadFactory original;


    public MyThreadFactory(ThreadFactory original) {
        this.original = original;
    }


    @Override
    public Thread newThread(Runnable r) {
        Thread thread = original.newThread(r);
        // 異常捕獲
        thread.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());//自定義的未捕獲異常處理器
        return thread;
    }
}

使用說明:在配置線程池時,把這個工廠傳遞給線程池,這樣線程池創(chuàng)建的所有線程都會具備異常捕獲能力。

3. ThreadPoolConfig 類

這是一個 Spring 配置類,用于創(chuàng)建和配置一個名為accountExecutor的線程池。

package com.hy.archive.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 自定義單列線程池配置類
 */
@Configuration
@EnableAsync
public class ThreadPoolConfig implements AsyncConfigurer {

    //自定義線程池名稱
    public static final String ACCOUNT_EXECUTOR = "accountExecutor";

    @Override
    public Executor getAsyncExecutor() {
        return accountExecutor();
    }

    @Bean(ACCOUNT_EXECUTOR)
    @Primary
    public ThreadPoolTaskExecutor accountExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(20);
        executor.setQueueCapacity(500);
        // 線程池優(yōu)雅停機(jī)的關(guān)鍵
        executor.setWaitForTasksToCompleteOnShutdown(true);
        // 線程池前綴配置
        executor.setThreadNamePrefix("account-exec-");
        //滿了調(diào)用線程執(zhí)行,認(rèn)為重要任務(wù)
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //設(shè)置線程池的異常處理邏輯使用了裝飾器設(shè)計模式
        executor.setThreadFactory(new MyThreadFactory(executor));
        executor.initialize();
        return executor;

    }
}

4.舉個案例如何使用

1.異步使用

假設(shè)你有一個異步服務(wù),使用該線程池執(zhí)行任務(wù):

@Service
public class MyAsyncService {

    @Async("accountExecutor") // 指定使用自定義線程池
    public CompletableFuture<String> processAccount(String accountId) {
        // 模擬業(yè)務(wù)邏輯
        if (accountId == null) {
            throw new RuntimeException("賬戶ID不能為空"); // 未捕獲異常
        }
        // 正常業(yè)務(wù)邏輯...
        return CompletableFuture.completedFuture("處理完成");
    }
}

當(dāng)調(diào)用 processAccount(null) 時,會觸發(fā)未捕獲異常,此時異常處理流程如下:

  • 線程池中的線程執(zhí)行任務(wù)時拋出 RuntimeException。
  • 由于線程已通過 MyThreadFactory 設(shè)置了 MyUncaughtExceptionHandler,異常會被該處理器捕獲。
  • MyUncaughtExceptionHandler 記錄錯誤日志(例如:Exception in thread account-exec-1: 賬戶ID不能為空)。
  • 可擴(kuò)展邏輯(如發(fā)送告警)被觸發(fā)。

2.結(jié)合 CompletableFuture

@Service
public class AccountService {

    @Autowired
    private ThreadPoolTaskExecutor accountExecutor; // 注入你的線程池

    public CompletableFuture<String> processAccount(String accountId) {
        return CompletableFuture.supplyAsync(() -> {
            // 模擬業(yè)務(wù)邏輯,可能拋出異常
            if (accountId == null) {
                throw new RuntimeException("賬戶ID不能為空");
            }
            // 正常處理邏輯...
            return "賬戶處理成功: " + accountId;
        }, accountExecutor) // 指定使用你的線程池
        .exceptionally(ex -> {
            // 處理異常的邏輯
            log.error("處理賬戶時發(fā)生異常: {}", ex.getMessage(), ex);
            return "處理失敗: " + ex.getMessage(); // 返回默認(rèn)值或錯誤信息
        });
    }
}

異常處理機(jī)制說明

  • supplyAsync + 指定線程池

使用 accountExecutor 線程池執(zhí)行異步任務(wù),該線程池已通過你的 MyThreadFactory 設(shè)置了 MyUncaughtExceptionHandler。

  • exceptionally 回調(diào)

當(dāng)任務(wù)拋出異常時,exceptionally 會捕獲異常并返回默認(rèn)值或處理結(jié)果。這是 CompletableFuture 提供的顯式異常處理方式。

雙重保障

  • 若未使用 exceptionally,異常會被你的 MyUncaughtExceptionHandler 捕獲(記錄日志并觸發(fā)告警)。
  • 若使用 exceptionally,異常會被顯式處理,同時 MyUncaughtExceptionHandler 仍會記錄日志(雙重保障)。

驗(yàn)證異常處理效果

@SpringBootTest
class AccountServiceTest {

    @Autowired
    private AccountService accountService;

    @Test
    void testExceptionHandling() throws Exception {
        // 模擬異常情況
        CompletableFuture<String> future = accountService.processAccount(null);
        
        // 驗(yàn)證異常處理結(jié)果
        String result = future.get(); // 不會拋出異常,因?yàn)閑xceptionally已處理
        assertEquals("處理失敗: 賬戶ID不能為空", result);
        
        // 檢查日志:MyUncaughtExceptionHandler也會記錄該異常
        // ERROR Exception in thread account-exec-1: 賬戶ID不能為空
    }
}

更復(fù)雜的異常處理鏈

CompletableFuture 提供了多種異常處理方法,可根據(jù)需求組合使用:

public CompletableFuture<String> processAccount(String accountId) {
    return CompletableFuture.supplyAsync(() -> {
        if (accountId == null) {
            throw new IllegalArgumentException("賬戶ID不能為空");
        }
        if (!isValid(accountId)) {
            throw new RuntimeException("賬戶ID無效");
        }
        return "賬戶處理成功: " + accountId;
    }, accountExecutor)
    .exceptionally(ex -> {
        if (ex instanceof IllegalArgumentException) {
            return "非法參數(shù): " + ex.getMessage();
        } else {
            return "系統(tǒng)錯誤: " + ex.getMessage();
        }
    })
    .thenApply(result -> {
        // 繼續(xù)處理結(jié)果
        return "最終結(jié)果: " + result;
    })
    .exceptionally(ex -> {
        // 處理后續(xù)步驟可能出現(xiàn)的異常
        return "處理失敗: " + ex.getMessage();
    });
}

關(guān)鍵區(qū)別:CompletableFuture vs 普通異步任務(wù)

場景異常處理方式是否需要 MyUncaughtExceptionHandler
普通異步任務(wù) (@Async)依賴 MyUncaughtExceptionHandler 統(tǒng)一處理必須配置
CompletableFuture + exceptionally顯式捕獲并處理異常可選(用于日志記錄和額外監(jiān)控)
CompletableFuture + 未處理異常依賴 MyUncaughtExceptionHandler 捕獲必須配置

最佳實(shí)踐建議

優(yōu)先使用 CompletableFuture 的顯式處理

在異步任務(wù)中,盡量通過 exceptionally()、handle()whenComplete() 顯式處理異常,使代碼更健壯。

保留統(tǒng)一異常處理器作為兜底

你的 MyUncaughtExceptionHandler 仍有價值,可用于記錄所有未被顯式處理的異常,避免遺漏問題。

區(qū)分可恢復(fù)異常和不可恢復(fù)異常

對不同類型的異常采取不同處理策略,例如:

.exceptionally(ex -> {
    if (ex instanceof RetryableException) {
        // 重試邏輯
        return retry(accountId);
    } else {
        // 記錄致命錯誤并返回默認(rèn)值
        log.error("致命錯誤", ex);
        return "默認(rèn)結(jié)果";
    }
})

總結(jié)

通過結(jié)合你的線程池配置和 CompletableFuture 的異常處理機(jī)制,你可以實(shí)現(xiàn):

  • 顯式異常處理:通過 exceptionally 等方法直接處理已知異常。
  • 統(tǒng)一日志記錄:利用 MyUncaughtExceptionHandler 記錄所有異常,確保無遺漏。
  • 靈活的錯誤恢復(fù):根據(jù)異常類型執(zhí)行不同的恢復(fù)邏輯。

這種組合方式既保證了代碼的健壯性,又便于問題追蹤和系統(tǒng)監(jiān)控。

以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Mybatis之動態(tài)SQL使用小結(jié)(全網(wǎng)最新)

    Mybatis之動態(tài)SQL使用小結(jié)(全網(wǎng)最新)

    MyBatis令人喜歡的一大特性就是動態(tài)SQL,?在使用JDBC的過程中,?根據(jù)條件進(jìn)行SQL的拼接是很麻煩且很容易出錯的,MyBatis通過OGNL來進(jìn)行動態(tài)SQL的使用解決了這個麻煩,對Mybatis動態(tài)SQL相關(guān)知識感興趣的朋友跟隨小編一起看看吧
    2024-05-05
  • Java字符串技巧之刪除標(biāo)點(diǎn)或最后字符的方法

    Java字符串技巧之刪除標(biāo)點(diǎn)或最后字符的方法

    這篇文章主要介紹了Java字符串技巧之刪除標(biāo)點(diǎn)或最后字符的方法,是Java入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下
    2015-11-11
  • Java toString方法重寫工具之ToStringBuilder案例詳解

    Java toString方法重寫工具之ToStringBuilder案例詳解

    這篇文章主要介紹了Java toString方法重寫工具之ToStringBuilder案例詳解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • springboot項(xiàng)目如何開啟https服務(wù)

    springboot項(xiàng)目如何開啟https服務(wù)

    這篇文章主要介紹了springboot項(xiàng)目如何開啟https服務(wù)方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • Python安裝Jupyter Notebook配置使用教程詳解

    Python安裝Jupyter Notebook配置使用教程詳解

    這篇文章主要介紹了Python安裝Jupyter Notebook配置使用教程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • 解決Spring?AOP攔截抽象類(父類)中方法失效問題

    解決Spring?AOP攔截抽象類(父類)中方法失效問題

    這篇文章主要介紹了解決Spring?AOP攔截抽象類(父類)中方法失效問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • SpringBoot啟動過程逐步分析講解

    SpringBoot啟動過程逐步分析講解

    這篇文章主要介紹了SpringBoot啟動過程的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2023-01-01
  • Netty源碼分析NioEventLoop初始化線程選擇器創(chuàng)建

    Netty源碼分析NioEventLoop初始化線程選擇器創(chuàng)建

    這篇文章主要介紹了Netty源碼分析NioEventLoop初始化線程選擇器創(chuàng)建,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-03-03
  • 解決IDEA創(chuàng)建maven項(xiàng)目時pom.xml沒有變藍(lán)的問題

    解決IDEA創(chuàng)建maven項(xiàng)目時pom.xml沒有變藍(lán)的問題

    這篇文章主要介紹了解決IDEA創(chuàng)建maven項(xiàng)目時pom.xml沒有變藍(lán)的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • Java編寫實(shí)現(xiàn)坦克大戰(zhàn)小游戲

    Java編寫實(shí)現(xiàn)坦克大戰(zhàn)小游戲

    這篇文章主要為大家詳細(xì)介紹了Java編寫實(shí)現(xiàn)坦克大戰(zhàn)小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01

最新評論

邓州市| 博湖县| 获嘉县| 博乐市| 车致| 青龙| 图木舒克市| 河北省| 监利县| 大英县| 岑巩县| 莱芜市| 湖南省| 巩义市| 平武县| 舒城县| 安图县| 阳曲县| 湖南省| 濮阳县| 和田市| 徐水县| 都安| 广东省| 长丰县| 浪卡子县| 泸溪县| 长治县| 黄山市| 平阴县| 湛江市| 贵州省| 文成县| 瑞金市| 华安县| 自治县| 新沂市| 濮阳县| 五家渠市| 邯郸市| 福海县|