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

基于SpringBoot多線程@Async的使用體驗(yàn)

 更新時(shí)間:2021年12月29日 10:41:43   作者:金陵砍柴人  
這篇文章主要介紹了SpringBoot多線程@Async的使用體驗(yàn),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

多線程@Async的使用體驗(yàn)

場景

導(dǎo)入:可以將大批量的數(shù)據(jù)insert操作采用多線程的方式并行執(zhí)行

第三方服務(wù)的接口調(diào)用:由于存在個(gè)別第三方服務(wù)調(diào)用比較耗時(shí)的場景,此時(shí)就可以與自身服務(wù)的邏輯并行執(zhí)行

簡而言之:接口中部份業(yè)務(wù)邏輯可以通過并行的方式來優(yōu)化接口性能

1.線程池配置

@Configuration
@EnableAsync
public class TaskPoolConfig {

    @Bean("taskExecutor") // bean 的名稱,默認(rèn)為首字母小寫的方法名
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //核心線程數(shù)(CPU核心數(shù)+1)
        executor.setCorePoolSize(10);
        //最大線程數(shù)(2*CPU核心數(shù)+1)
        executor.setMaxPoolSize(20);
        //緩沖隊(duì)列數(shù)
        executor.setQueueCapacity(200);
        //允許線程空閑時(shí)間(單位:默認(rèn)為秒)
        executor.setKeepAliveSeconds(60);
        //線程池名前綴
        executor.setThreadNamePrefix("sub-thread-");
        // 增加 TaskDecorator 屬性的配置
        executor.setTaskDecorator(new ContextDecorator());
        // 線程池對拒絕任務(wù)的處理策略:CallerRunsPolicy:不在新線程中執(zhí)行任務(wù),而是由調(diào)用者所在的線程來執(zhí)行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
}

2.子父線程之間共享一個(gè)Request的配置方案

1.實(shí)現(xiàn)TaskDecorator接口

/**
 * 子線程裝飾器
 *
 * @author Da Shuai
 * @date 2021-06-10 18:28:17
 */
public class SubThreadTaskDecorator implements TaskDecorator {

    @Override
    public Runnable decorate(Runnable runnable) {
        RequestAttributes context = RequestContextHolder.currentRequestAttributes();
        return () -> {
            try {
                RequestContextHolder.setRequestAttributes(context);
                runnable.run();
            } finally {
                RequestContextHolder.resetRequestAttributes();
            }
        };
    }
}

2.之前的線程池配置加如下代碼使其生效

// 增加 TaskDecorator 屬性的配置
executor.setTaskDecorator(new ContextDecorator());

3.阻塞主線程,等待所有子線程執(zhí)行完畢后繼續(xù)執(zhí)行主線程

1.CountDownLatch

思路:

  • 實(shí)例化CountDownLatch對象,同時(shí)傳入x(線程數(shù)量:這個(gè)數(shù)量必須等于子線程數(shù)量)進(jìn)行構(gòu)造
  • 每個(gè)子線程執(zhí)行完畢后會調(diào)用countDown()方法
  • 子線程邏輯后方調(diào)用await()方法

這樣線程計(jì)數(shù)器為0之前,主線程就一直處于pending狀態(tài)

主線程邏輯

new CountDownLatch(X)
latch.await()
@Override
@Transactional
public void importExcel(File file) {
    CountDownLatch latch = new CountDownLatch(3);
    for (int i = 0; i < 3; i++) {
        VoteDO voteDO = new VoteDO();
        voteDO.setTitle(i + "");
        asyncManager.asyncSaveVote(voteDO);
    }
    //System.out.println(1/0);
    try {
        latch.await();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

子線程邏輯

latch.countDown()
@Override
@Async
public void asyncSaveVote(VoteDO voteDO, CountDownLatch latch) {
    log.info("當(dāng)前線程為 {},休眠10s開始", Thread.currentThread().getName());
    try {
        Thread.sleep(10000L);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    log.info("當(dāng)前線程為 {},休眠10s結(jié)束", Thread.currentThread().getName());
    log.info("當(dāng)前線程為 {},保存開始", Thread.currentThread().getName());
    voteDO.setDesc(Thread.currentThread().getName());
    voteDao.insert(voteDO);
    latch.countDown();
    log.info("當(dāng)前線程為 {},保存結(jié)束", Thread.currentThread().getName());
}

日志

2021-06-11 16:31:08.653 INFO 27516 --- [nio-8080-exec-1] com.zhdj.config.LogAspect : ===============請求內(nèi)容===============
2021-06-11 16:31:08.653 INFO 27516 --- [nio-8080-exec-1] com.zhdj.config.LogAspect : 請求地址:http://localhost:8080/api/import
2021-06-11 16:31:08.653 INFO 27516 --- [nio-8080-exec-1] com.zhdj.config.LogAspect : 請求方式:POST
2021-06-11 16:31:08.655 INFO 27516 --- [nio-8080-exec-1] com.zhdj.config.LogAspect : 請求類方法:com.zhdj.controller.ImportController.importExcel
2021-06-11 16:31:08.655 INFO 27516 --- [nio-8080-exec-1] com.zhdj.config.LogAspect : 請求類方法參數(shù):[org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile@42c3f403]
2021-06-11 16:31:08.655 INFO 27516 --- [nio-8080-exec-1] com.zhdj.config.LogAspect : ===============請求內(nèi)容===============
2021-06-11 16:31:08.676 INFO 27516 --- [nio-8080-exec-1] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2021-06-11 16:31:08.894 INFO 27516 --- [nio-8080-exec-1] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2021-06-11 16:31:08.921 INFO 27516 --- [ sub-thread-3] com.zhdj.AsyncManagerImpl : 當(dāng)前線程為 sub-thread-3,休眠10s開始
2021-06-11 16:31:08.921 INFO 27516 --- [ sub-thread-1] com.zhdj.AsyncManagerImpl : 當(dāng)前線程為 sub-thread-1,休眠10s開始
2021-06-11 16:31:08.921 INFO 27516 --- [ sub-thread-2] com.zhdj.AsyncManagerImpl : 當(dāng)前線程為 sub-thread-2,休眠10s開始
2021-06-11 16:31:18.921 INFO 27516 --- [ sub-thread-2] com.zhdj.AsyncManagerImpl : 當(dāng)前線程為 sub-thread-2,休眠10s結(jié)束
2021-06-11 16:31:18.921 INFO 27516 --- [ sub-thread-3] com.zhdj.AsyncManagerImpl : 當(dāng)前線程為 sub-thread-3,休眠10s結(jié)束
2021-06-11 16:31:18.921 INFO 27516 --- [ sub-thread-2] com.zhdj.AsyncManagerImpl : 當(dāng)前線程為 sub-thread-2,保存開始
2021-06-11 16:31:18.921 INFO 27516 --- [ sub-thread-1] com.zhdj.AsyncManagerImpl : 當(dāng)前線程為 sub-thread-1,休眠10s結(jié)束
2021-06-11 16:31:18.921 INFO 27516 --- [ sub-thread-3] com.zhdj.AsyncManagerImpl : 當(dāng)前線程為 sub-thread-3,保存開始
2021-06-11 16:31:18.921 INFO 27516 --- [ sub-thread-1] com.zhdj.AsyncManagerImpl : 當(dāng)前線程為 sub-thread-1,保存開始
2021-06-11 16:31:19.080 DEBUG 27516 --- [ sub-thread-3] com.zhdj.dao.VoteDao.insert : ==> Preparing: INSERT INTO vote ( title, `desc`, gmt_create, gmt_modified ) VALUES ( ?, ?, ?, ? )
2021-06-11 16:31:19.080 DEBUG 27516 --- [ sub-thread-1] com.zhdj.dao.VoteDao.insert : ==> Preparing: INSERT INTO vote ( title, `desc`, gmt_create, gmt_modified ) VALUES ( ?, ?, ?, ? )
2021-06-11 16:31:19.080 DEBUG 27516 --- [ sub-thread-2] com.zhdj.dao.VoteDao.insert : ==> Preparing: INSERT INTO vote ( title, `desc`, gmt_create, gmt_modified ) VALUES ( ?, ?, ?, ? )
2021-06-11 16:31:19.156 DEBUG 27516 --- [ sub-thread-1] com.zhdj.dao.VoteDao.insert : ==> Parameters: 0(String), sub-thread-1(String), 2021-06-11T16:31:19.032(LocalDateTime), 2021-06-11T16:31:19.037(LocalDateTime)
2021-06-11 16:31:19.156 DEBUG 27516 --- [ sub-thread-3] com.zhdj.dao.VoteDao.insert : ==> Parameters: 2(String), sub-thread-3(String), 2021-06-11T16:31:19.032(LocalDateTime), 2021-06-11T16:31:19.037(LocalDateTime)
2021-06-11 16:31:19.156 DEBUG 27516 --- [ sub-thread-2] com.zhdj.dao.VoteDao.insert : ==> Parameters: 1(String), sub-thread-2(String), 2021-06-11T16:31:19.032(LocalDateTime), 2021-06-11T16:31:19.037(LocalDateTime)
2021-06-11 16:31:19.172 DEBUG 27516 --- [ sub-thread-3] com.zhdj.dao.VoteDao.insert : <== Updates: 1
2021-06-11 16:31:19.178 DEBUG 27516 --- [ sub-thread-2] com.zhdj.dao.VoteDao.insert : <== Updates: 1
2021-06-11 16:31:19.187 DEBUG 27516 --- [ sub-thread-1] com.zhdj.dao.VoteDao.insert : <== Updates: 1
2021-06-11 16:31:19.224 INFO 27516 --- [ sub-thread-3] com.zhdj.AsyncManagerImpl : 當(dāng)前線程為 sub-thread-3,保存結(jié)束
2021-06-11 16:31:19.224 INFO 27516 --- [ sub-thread-1] com.zhdj.AsyncManagerImpl : 當(dāng)前線程為 sub-thread-1,保存結(jié)束
2021-06-11 16:31:19.224 INFO 27516 --- [ sub-thread-2] com.zhdj.AsyncManagerImpl : 當(dāng)前線程為 sub-thread-2,保存結(jié)束
2021-06-11 16:31:19.226 INFO 27516 --- [nio-8080-exec-1] com.zhdj.config.LogAspect : --------------返回內(nèi)容----------------
2021-06-11 16:31:19.328 INFO 27516 --- [nio-8080-exec-1] com.zhdj.config.LogAspect : Response內(nèi)容:null
2021-06-11 16:31:19.328 INFO 27516 --- [nio-8080-exec-1] com.zhdj.config.LogAspect : --------------返回內(nèi)容----------------

2.Future

思路:

1.子線程邏輯返回Future對象

2.主線程邏輯循環(huán)判斷每個(gè)子線程返回的Future對象isDone()是否為true

主線程邏輯

循環(huán)判斷future.isDone()是否為true

@Override
@Transactional
public void importExcel(File file) {
 List<Future> futureList = new ArrayList<>();
 for (int i = 0; i < 3; i++) {
     VoteDO voteDO = new VoteDO();
     voteDO.setTitle(i + "");
     Future future = asyncManager.asyncSaveVote(voteDO);
     futureList.add(future);
 }
 //檢查所有子線程是否均執(zhí)行完畢
 while (true) {
     boolean isAllDone = true;
     for (Future future : futureList) {
         if (null == future || !future.isDone()) {
             isAllDone = false;
         }
     }
     if (isAllDone) {
         log.info("所有子線程執(zhí)行完畢");
         break;
     }
 }
}

子線程邏輯

返回Future對象

@Override
public Future asyncSaveVote(VoteDO voteDO) {
    log.info("當(dāng)前線程為 {},休眠10s開始", Thread.currentThread().getName());
    try {
        Thread.sleep(10000L);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    log.info("當(dāng)前線程為 {},休眠10s結(jié)束", Thread.currentThread().getName());
    log.info("當(dāng)前線程為 {},保存開始", Thread.currentThread().getName());
    voteDO.setDesc(Thread.currentThread().getName());
    voteDao.insert(voteDO);
    log.info("當(dāng)前線程為 {},保存結(jié)束", Thread.currentThread().getName());
    //返回需要用AsyncResult類
    return new AsyncResult<>(true);
}

日志

2021-06-11 16:42:28.974 INFO 20492 --- [nio-8080-exec-2] com.zhdj.config.LogAspect : ===============請求內(nèi)容===============
2021-06-11 16:42:28.974 INFO 20492 --- [nio-8080-exec-2] com.zhdj.config.LogAspect : 請求地址:http://localhost:8080/api/import
2021-06-11 16:42:28.974 INFO 20492 --- [nio-8080-exec-2] com.zhdj.config.LogAspect : 請求方式:POST
2021-06-11 16:42:28.975 INFO 20492 --- [nio-8080-exec-2] com.zhdj.config.LogAspect : 請求類方法:com.zhdj.controller.ImportController.importExcel
2021-06-11 16:42:28.975 INFO 20492 --- [nio-8080-exec-2] com.zhdj.config.LogAspect : 請求類方法參數(shù):[org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile@7e23bacc]
2021-06-11 16:42:28.975 INFO 20492 --- [nio-8080-exec-2] com.zhdj.config.LogAspect : ===============請求內(nèi)容===============
2021-06-11 16:42:28.979 INFO 20492 --- [ sub-thread-5] com.zhdj.AsyncManagerImpl : 當(dāng)前線程為 sub-thread-5,休眠10s開始
2021-06-11 16:42:28.979 INFO 20492 --- [ sub-thread-4] com.zhdj.AsyncManagerImpl : 當(dāng)前線程為 sub-thread-4,休眠10s開始
2021-06-11 16:42:28.979 INFO 20492 --- [ sub-thread-6] com.zhdj.AsyncManagerImpl : 當(dāng)前線程為 sub-thread-6,休眠10s開始
2021-06-11 16:42:38.980 INFO 20492 --- [ sub-thread-6] com.zhdj.AsyncManagerImpl : 當(dāng)前線程為 sub-thread-6,休眠10s結(jié)束
2021-06-11 16:42:38.980 INFO 20492 --- [ sub-thread-4] com.zhdj.AsyncManagerImpl : 當(dāng)前線程為 sub-thread-4,休眠10s結(jié)束
2021-06-11 16:42:38.980 INFO 20492 --- [ sub-thread-5] com.zhdj.AsyncManagerImpl : 當(dāng)前線程為 sub-thread-5,休眠10s結(jié)束
2021-06-11 16:42:38.980 INFO 20492 --- [ sub-thread-6] com.zhdj.AsyncManagerImpl : 當(dāng)前線程為 sub-thread-6,保存開始
2021-06-11 16:42:38.980 INFO 20492 --- [ sub-thread-5] com.zhdj.AsyncManagerImpl : 當(dāng)前線程為 sub-thread-5,保存開始
2021-06-11 16:42:38.980 INFO 20492 --- [ sub-thread-4] com.zhdj.AsyncManagerImpl : 當(dāng)前線程為 sub-thread-4,保存開始
2021-06-11 16:42:38.981 DEBUG 20492 --- [ sub-thread-4] com.zhdj.dao.VoteDao.insert : ==> Preparing: INSERT INTO vote ( title, `desc`, gmt_create, gmt_modified ) VALUES ( ?, ?, ?, ? )
2021-06-11 16:42:38.981 DEBUG 20492 --- [ sub-thread-5] com.zhdj.dao.VoteDao.insert : ==> Preparing: INSERT INTO vote ( title, `desc`, gmt_create, gmt_modified ) VALUES ( ?, ?, ?, ? )
2021-06-11 16:42:38.981 DEBUG 20492 --- [ sub-thread-6] com.zhdj.dao.VoteDao.insert : ==> Preparing: INSERT INTO vote ( title, `desc`, gmt_create, gmt_modified ) VALUES ( ?, ?, ?, ? )
2021-06-11 16:42:38.982 DEBUG 20492 --- [ sub-thread-5] com.zhdj.dao.VoteDao.insert : ==> Parameters: 1(String), sub-thread-5(String), 2021-06-11T16:42:38.980(LocalDateTime), 2021-06-11T16:42:38.981(LocalDateTime)
2021-06-11 16:42:38.982 DEBUG 20492 --- [ sub-thread-4] com.zhdj.dao.VoteDao.insert : ==> Parameters: 0(String), sub-thread-4(String), 2021-06-11T16:42:38.980(LocalDateTime), 2021-06-11T16:42:38.981(LocalDateTime)
2021-06-11 16:42:38.982 DEBUG 20492 --- [ sub-thread-6] com.zhdj.dao.VoteDao.insert : ==> Parameters: 2(String), sub-thread-6(String), 2021-06-11T16:42:38.980(LocalDateTime), 2021-06-11T16:42:38.981(LocalDateTime)
2021-06-11 16:42:38.988 DEBUG 20492 --- [ sub-thread-5] com.zhdj.dao.VoteDao.insert : <== Updates: 1
2021-06-11 16:42:38.989 INFO 20492 --- [ sub-thread-5] com.zhdj.AsyncManagerImpl : 當(dāng)前線程為 sub-thread-5,保存結(jié)束
2021-06-11 16:42:38.993 DEBUG 20492 --- [ sub-thread-6] com.zhdj.dao.VoteDao.insert : <== Updates: 1
2021-06-11 16:42:38.993 INFO 20492 --- [ sub-thread-6] com.zhdj.AsyncManagerImpl : 當(dāng)前線程為 sub-thread-6,保存結(jié)束
2021-06-11 16:42:39.004 DEBUG 20492 --- [ sub-thread-4] com.zhdj.dao.VoteDao.insert : <== Updates: 1
2021-06-11 16:42:39.005 INFO 20492 --- [ sub-thread-4] com.zhdj.AsyncManagerImpl : 當(dāng)前線程為 sub-thread-4,保存結(jié)束
2021-06-11 16:42:39.005 INFO 20492 --- [nio-8080-exec-2] com.zhdj.service.impl.VoteServiceImpl : 所有子線程執(zhí)行完畢
2021-06-11 16:42:39.005 INFO 20492 --- [nio-8080-exec-2] com.zhdj.config.LogAspect : --------------返回內(nèi)容----------------
2021-06-11 16:42:39.005 INFO 20492 --- [nio-8080-exec-2] com.zhdj.config.LogAspect : Response內(nèi)容:null
2021-06-11 16:42:39.005 INFO 20492 --- [nio-8080-exec-2] com.zhdj.config.LogAspect : --------------返回內(nèi)容----------------

4.多線程共用一個(gè)事務(wù)

暫時(shí)無解決方案,這是弊端

異步調(diào)用@Async問題

1.使用背景

在項(xiàng)目中,當(dāng)訪問其他人的接口較慢或者做耗時(shí)任務(wù)時(shí),不想程序一直卡在耗時(shí)任務(wù)上,想程序能夠并行執(zhí)行,我們可以使用多線程來并行的處理任務(wù),也可以使用spring提供的異步處理方式@Async。

2.異步處理方式

調(diào)用之后,不返回任何數(shù)據(jù)。

調(diào)用之后,返回?cái)?shù)據(jù),通過Future來獲取返回?cái)?shù)據(jù)

3.@Async不返回?cái)?shù)據(jù)

使用@EnableAsync啟用異步注解

@Configuration
@EnableAsync
@Slf4j
public class AsyncConfig{
}

在異步處理的方法dealNoReturnTask上添加注解@Async

@Component
@Slf4j
public class AsyncTask {

    @Async
    public void dealNoReturnTask(){
        log.info("Thread {} deal No Return Task start", Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("Thread {} deal No Return Task end at {}", Thread.currentThread().getName(), System.currentTimeMillis());
    }
}

Test測試類:

@SpringBootTest(classes = SpringbootApplication.class)
@RunWith(SpringJUnit4ClassRunner.class)
@Slf4j
public class AsyncTest {
    @Autowired
    private AsyncTask asyncTask;

    @Test
    public void testDealNoReturnTask(){
        asyncTask.dealNoReturnTask();
        try {
            log.info("begin to deal other Task!");
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

日志打印結(jié)果為:

begin to deal other Task!
AsyncExecutorThread-1 deal No Return Task start
AsyncExecutorThread-1 deal No Return Task end at 1499751227034

從日志中我們可以看出,方法dealNoReturnTask()是異步執(zhí)行完成的。

dealNoReturnTask()設(shè)置sleep 3s是為了模擬耗時(shí)任務(wù)

testDealNoReturnTask()設(shè)置sleep 10s是為了確認(rèn)異步是否執(zhí)行完成

4.@Async返回?cái)?shù)據(jù)

異步調(diào)用返回?cái)?shù)據(jù),F(xiàn)uture表示在未來某個(gè)點(diǎn)獲取執(zhí)行結(jié)果,返回?cái)?shù)據(jù)類型可以自定義

    @Async
    public Future<String> dealHaveReturnTask() {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("thread", Thread.currentThread().getName());
        jsonObject.put("time", System.currentTimeMillis());
        return new AsyncResult<String>(jsonObject.toJSONString());
    }

測試類用isCancelled判斷異步任務(wù)是否取消,isDone判斷任務(wù)是否執(zhí)行結(jié)束

    @Test
    public void testDealHaveReturnTask() throws Exception {

        Future<String> future = asyncTask.dealHaveReturnTask();
        log.info("begin to deal other Task!");
        while (true) {
            if(future.isCancelled()){
                log.info("deal async task is Cancelled");
                break;
            }
            if (future.isDone() ) {
                log.info("deal async task is Done");
                log.info("return result is " + future.get());
                break;
            }
            log.info("wait async task to end ...");
            Thread.sleep(1000);
        }
    }

日志打印如下,我們可以看出任務(wù)一直在等待異步任務(wù)執(zhí)行完畢,用future.get()來獲取異步任務(wù)的返回結(jié)果

begin to deal other Task!
wait async task to end ...
wait async task to end ...
wait async task to end ...
wait async task to end ...
deal async task is Done
return result is {"thread":"AsyncExecutorThread-1","time":1499752617330}

5.異常處理

我們可以實(shí)現(xiàn)AsyncConfigurer接口,也可以繼承AsyncConfigurerSupport類來實(shí)現(xiàn)

在方法getAsyncExecutor()中創(chuàng)建線程池的時(shí)候,必須使用 executor.initialize(),

不然在調(diào)用時(shí)會報(bào)線程池未初始化的異常。

如果使用threadPoolTaskExecutor()來定義bean,則不需要初始化

@Configuration
@EnableAsync
@Slf4j
public class AsyncConfig implements AsyncConfigurer {

//    @Bean
//    public ThreadPoolTaskExecutor threadPoolTaskExecutor(){
//        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//        executor.setCorePoolSize(10);
//        executor.setMaxPoolSize(100);
//        executor.setQueueCapacity(100);
//        return executor;
//    }

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(100);
        executor.setQueueCapacity(100);
        executor.setThreadNamePrefix("AsyncExecutorThread-");
        executor.initialize(); //如果不初始化,導(dǎo)致找到不到執(zhí)行器
        return executor;
    }
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new AsyncExceptionHandler();
    }
}

異步異常處理類:

@Slf4j
public class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
    @Override
    public void handleUncaughtException(Throwable ex, Method method, Object... params) {
        log.info("Async method: {} has uncaught exception,params:{}", method.getName(), JSON.toJSONString(params));

        if (ex instanceof AsyncException) {
            AsyncException asyncException = (AsyncException) ex;
            log.info("asyncException:{}",asyncException.getErrorMessage());
        }

        log.info("Exception :");
        ex.printStackTrace();
    }
}

異步處理異常類:

@Data
@AllArgsConstructor
public class AsyncException extends Exception {
    private int code;
    private String errorMessage;
}

在無返回值的異步調(diào)用中,異步處理拋出異常,AsyncExceptionHandler的handleUncaughtException()會捕獲指定異常,原有任務(wù)還會繼續(xù)運(yùn)行,直到結(jié)束。

在有返回值的異步調(diào)用中,異步處理拋出異常,會直接拋出異常,異步任務(wù)結(jié)束,原有處理結(jié)束執(zhí)行。

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

相關(guān)文章

  • 詳解Java中-classpath和路徑的使用

    詳解Java中-classpath和路徑的使用

    本篇文章主要介紹了Java中-classpath和路徑的使用,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-04-04
  • Java案例之隨機(jī)驗(yàn)證碼功能實(shí)現(xiàn)實(shí)例

    Java案例之隨機(jī)驗(yàn)證碼功能實(shí)現(xiàn)實(shí)例

    本篇文章主要介紹了Java案例之隨機(jī)驗(yàn)證碼功能實(shí)現(xiàn)實(shí)例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-06-06
  • springcloud gateway網(wǎng)關(guān)服務(wù)啟動報(bào)錯(cuò)的解決

    springcloud gateway網(wǎng)關(guān)服務(wù)啟動報(bào)錯(cuò)的解決

    這篇文章主要介紹了springcloud gateway網(wǎng)關(guān)服務(wù)啟動報(bào)錯(cuò)的解決,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • 關(guān)于Springboot數(shù)據(jù)庫配置文件明文密碼加密解密的問題

    關(guān)于Springboot數(shù)據(jù)庫配置文件明文密碼加密解密的問題

    這篇文章主要介紹了Springboot數(shù)據(jù)庫配置文件明文密碼加密解密的問題,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-03-03
  • Java集合教程之Collection實(shí)例詳解

    Java集合教程之Collection實(shí)例詳解

    集合,或者叫容器,是一個(gè)包含多個(gè)元素的對象,下面這篇文章主要給大家介紹了關(guān)于Java集合教程之Collection的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2018-08-08
  • 基于springboot i18n國際化后臺多種語言設(shè)置的方式

    基于springboot i18n國際化后臺多種語言設(shè)置的方式

    這篇文章主要介紹了基于springboot i18n國際化后臺多種語言設(shè)置的方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • 使用springboot每日推送早安問候語到用戶微信的全過程

    使用springboot每日推送早安問候語到用戶微信的全過程

    近期網(wǎng)上又出現(xiàn)一股給女朋友做微信公眾號推送的潮流,所以這篇文章主要給大家介紹了關(guān)于如何使用springboot每日推送早安問候語到用戶微信的相關(guān)資料,文中通過圖文以及實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-11-11
  • 關(guān)于feign.codec.DecodeException異常的解決方案

    關(guān)于feign.codec.DecodeException異常的解決方案

    這篇文章主要介紹了關(guān)于feign.codec.DecodeException異常的解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • SpringBoot實(shí)現(xiàn)對Http接口進(jìn)行監(jiān)控的代碼

    SpringBoot實(shí)現(xiàn)對Http接口進(jìn)行監(jiān)控的代碼

    Spring Boot Actuator是Spring Boot提供的一個(gè)模塊,用于監(jiān)控和管理Spring Boot應(yīng)用程序的運(yùn)行時(shí)信息,本文將介紹一下Spring Boot Actuator以及代碼示例,以及如何進(jìn)行接口請求監(jiān)控,需要的朋友可以參考下
    2024-07-07
  • Java多線程中Lock鎖的使用小結(jié)

    Java多線程中Lock鎖的使用小結(jié)

    這篇文章主要介紹了Java多線程中Lock鎖的使用小結(jié),本節(jié)主要講了它的基本使用,大家可以舉一反三,試試什么條件下會導(dǎo)致死鎖,需要的朋友可以參考下
    2022-06-06

最新評論

怀来县| 安溪县| 东源县| 六盘水市| 禹州市| 迭部县| 黎平县| 辛集市| 寿宁县| 静乐县| 秦皇岛市| 勃利县| 伊金霍洛旗| 山丹县| 页游| 双牌县| 肥城市| 新昌县| 白银市| 尼玛县| 平和县| 宝鸡市| 东乡族自治县| 澜沧| 北碚区| 普宁市| 伊吾县| 固镇县| 常德市| 邵东县| 西乌| 仪征市| 海南省| 鞍山市| 哈尔滨市| 淳安县| 广州市| 平昌县| 濮阳市| 南宫市| 华阴市|