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

SpringBoot執(zhí)行有返回值的異步任務(wù)問(wèn)題

 更新時(shí)間:2023年07月20日 08:40:11   作者:章魚(yú)先森cd  
這篇文章主要介紹了SpringBoot執(zhí)行有返回值的異步任務(wù)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

SpringBoot執(zhí)行有返回值異步任務(wù)

Springboot如何使用多線程處理異步任務(wù),并且是代返回值的。

比如,我一個(gè)Controller層的接口,調(diào)用到Service層,在對(duì)應(yīng)的Service方法中有三個(gè)方法,這三個(gè)方法都是去調(diào)Dao層查詢數(shù)據(jù)庫(kù)數(shù)據(jù),每個(gè)查詢平均耗時(shí)5s,最后將這三個(gè)查詢的結(jié)果進(jìn)行合并計(jì)算。如果不采用異步查詢的至少需要15s的時(shí)間來(lái)處理這個(gè)請(qǐng)求。此時(shí)我們可以使用異步任務(wù)方式來(lái)操作,可以減少10s左右的時(shí)間。

在Springboot中使用異步需要開(kāi)啟異步支持(@EnableAsync),代碼如下

@SpringBootApplication
@EnableAsync
public class PublisherApplication {
? ? public static void main(String[] args) {
? ? ? ? SpringApplication.run(PublisherApplication.class, args);
? ? }
}

然后增加一個(gè)配置類(lèi),不過(guò)這個(gè)Springboot也會(huì)默認(rèn)配置,一般我們使用線程池是都不使用默認(rèn)的,而是使用自定義的:

/**
?* @author Mr. Zhang
?* @description 異步線程池
?* @date 2019-04-19 14:21
?* @website https://www.zhangguimin.cn
?*/
@Configuration
public class AsyncConfig {
? ? private static final int THREADS = Runtime.getRuntime().availableProcessors();
? ? @Bean("taskExecutor")
? ? public Executor execute() {
? ? ? ? System.out.println(THREADS);
? ? ? ? Executor executor = new ThreadPoolExecutor(THREADS, 2 * THREADS, 5, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1024));
? ? ? ? return executor;
? ? }
}

此配置為IO密集型服務(wù)器參數(shù),即最大線程數(shù)為CPU核數(shù)*2(THREADS為CPU核數(shù)),其他拒絕策略默認(rèn)即可。

在之后的異步任務(wù)中使用此出定義的線程池taskExecutor。

然后就是異步任務(wù),在對(duì)應(yīng)的任務(wù)方法上標(biāo)注@Async(“taskExecutor”)即可,表示使用taskExecutor線程池中線程執(zhí)行異步任務(wù)。代碼參考:

@Service
public class TaskServer {
? ? @Async("taskExecutor")
? ? public Future<Integer> asyncTask(CountDownLatch latch) {
? ? ? ? try {
? ? ? ? ? ? Thread.sleep(3000L);
? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }finally {
? ? ? ? ? ? latch.countDown();
? ? ? ? }
? ? ? ? return new AsyncResult<>(10);
? ? }
? ? @Async("taskExecutor")
? ? public Future<Integer> asyncTask2(CountDownLatch latch) {
? ? ? ? try {
? ? ? ? ? ? Thread.sleep(3000L);
? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }finally {
? ? ? ? ? ? latch.countDown();
? ? ? ? }
? ? ? ? return new AsyncResult<>(20);
? ? }
? ? @Async("taskExecutor")
? ? public Future<Integer> asyncTask3(CountDownLatch latch) {
? ? ? ? try {
? ? ? ? ? ? Thread.sleep(3000L);
? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }finally {
? ? ? ? ? ? latch.countDown();
? ? ? ? }
? ? ? ? return new AsyncResult<>(30);
? ? }
}

注意的是,需要在類(lèi)上標(biāo)注為組件注解,此處為@Service。

在這三個(gè)方法中執(zhí)行sleep,使線程都是sleep 3秒的時(shí)間。然后參數(shù)為CountDownLatch,在每次執(zhí)行完就countDown(),然后返回值為Future,如果執(zhí)行的異步方法沒(méi)有返回值可以不需要CountDownLatch和返回值就行。

在對(duì)應(yīng)的測(cè)試類(lèi)中執(zhí)行

@RunWith(SpringRunner.class)
@SpringBootTest
public class PublisherApplicationTests {
? ? @Autowired
? ? private TaskServer taskServer;
? ? @Test
? ? public void test() {
? ? ? ? CountDownLatch latch = new CountDownLatch(3);
? ? ? ? LocalTime time = LocalTime.now();
? ? ? ? Future<Integer> integerFuture = taskServer.asyncTask(latch);
? ? ? ? Future<Integer> integerFuture1 = taskServer.asyncTask2(latch);
? ? ? ? Future<Integer> integerFuture2 = taskServer.asyncTask3(latch);
? ? ? ? try {
? ? ? ? ? ? latch.await();
? ? ? ? ? ? LocalTime end =LocalTime.now();
? ? ? ? ? ? System.out.println(Duration.between(time, end));
? ? ? ? ? ? Integer integer = integerFuture.get();
? ? ? ? ? ? Integer integer1 = integerFuture1.get();
? ? ? ? ? ? Integer integer2 = integerFuture2.get();
? ? ? ? ? ? int i = integer + integer1 + integer2;
? ? ? ? ? ? System.out.println(i);
? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? } catch (ExecutionException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }
? ? }
}

注意CountDownLatch latch = new CountDownLatch(3);有三個(gè)異步方法傳入的值為3,在調(diào)用的異步方法后面需要latch.await();

一定不要在latch.await();前去get()結(jié)果值,這樣會(huì)導(dǎo)致異步方法強(qiáng)制執(zhí)行。

另外,有的人也使用while循環(huán),在所有結(jié)果出來(lái)前一致在循環(huán)等待,類(lèi)似自旋鎖的原理,對(duì)資源消耗較高,還有,如果一個(gè)任務(wù)出現(xiàn)錯(cuò)誤,就可能會(huì)造成一只循環(huán)。而CountDownLatch可在await()方法中傳入等待時(shí)間,如果超過(guò)這個(gè)時(shí)間就會(huì)結(jié)束等待,直接完成下面的操作。

SpringBoot開(kāi)啟有返回值的異步調(diào)用:三步搞定

1、線程池配置

package com.listen.demo.config;
/**
 * @author liuxd
 * @version 1.0
 * @date 2019-12-25 15:46
 */
import com.listen.demo.service.MyTaskServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
@Configuration
//@ComponentScan({"com.listen.demo"})
@EnableAsync
public class ExecutorConfig {
    private static final Logger logger = LoggerFactory.getLogger(ExecutorConfig.class);
    @Bean
    public Executor asyncServiceExecutor() {
        logger.info("start asyncServiceExecutor");
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //配置核心線程數(shù)
        executor.setCorePoolSize(5);
        //配置最大線程數(shù)
        executor.setMaxPoolSize(5);
        //配置隊(duì)列大小
        executor.setQueueCapacity(99999);
        //配置線程池中的線程的名稱前綴
        executor.setThreadNamePrefix("async-service-");
        // rejection-policy:當(dāng)pool已經(jīng)達(dá)到max size的時(shí)候,如何處理新任務(wù)
        // CALLER_RUNS:不在新線程中執(zhí)行任務(wù),而是有調(diào)用者所在的線程來(lái)執(zhí)行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //執(zhí)行初始化
        executor.initialize();
        return executor;
    }
    @Bean
    public MyTaskServer myTaskServer(){
        return new MyTaskServer();
    }
}

2、業(yè)務(wù)操作類(lèi)

package com.listen.demo.service;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
/**
 * @author liuxd
 * @version 1.0
 * @date 2019-12-25 15:48
 */
@Service
public class MyTaskServer {
    @Async("asyncServiceExecutor")
    public Future<Integer> asyncTask(CountDownLatch countDownLatch) throws Exception {
        Thread.sleep(1000L);
        countDownLatch.countDown();
        return new AsyncResult<>(10);
    }
    @Async("asyncServiceExecutor")
    public Future<Integer> asyncTask2(CountDownLatch countDownLatch) throws Exception {
        Thread.sleep(2000L);
        countDownLatch.countDown();
        return new AsyncResult<>(20);
    }
    @Async("asyncServiceExecutor")
    public Future<Integer> asyncTask3(CountDownLatch countDownLatch) throws Exception {
        Thread.sleep(3000L);
        countDownLatch.countDown();
        return new AsyncResult<>(30);
    }
}
 

3、異步+等待+有返回的測(cè)試類(lèi)

package com.listen.demo;
import com.listen.demo.config.ExecutorConfig;
import com.listen.demo.service.MyTaskServer;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
/**
 * @author liuxd
 * @version 1.0
 * @date 2019-12-25 16:03
 */
public class TestAsyncTask {
    public static void main(String[] args) throws Exception {
        System.out.println("主線程:" + Thread.currentThread().getName() + "開(kāi)始執(zhí)行調(diào)用任務(wù)...");
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ExecutorConfig.class);
        MyTaskServer myTaskServer = context.getBean(MyTaskServer.class);
        CountDownLatch countDownLatch = new CountDownLatch(3);
        Future<Integer> future1 = myTaskServer.asyncTask(countDownLatch);
        Future<Integer> future2 = myTaskServer.asyncTask2(countDownLatch);
        Future<Integer> future3 = myTaskServer.asyncTask3(countDownLatch);
        countDownLatch.await();
        Integer num1 = future1.get();
        Integer num2 = future2.get();
        Integer num3 = future3.get();
        int data = num1 + num2 + num3;
        System.out.println("最終匯總計(jì)算結(jié)果:" + data);
        context.close();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("主線程:" + Thread.currentThread().getName() + "程序結(jié)束!!");
    }
}

總結(jié)

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

相關(guān)文章

  • WebSocket實(shí)現(xiàn)Web聊天室功能

    WebSocket實(shí)現(xiàn)Web聊天室功能

    這篇文章主要為大家詳細(xì)介紹了WebSocket實(shí)現(xiàn)Web聊天室功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-08-08
  • 深度思考JDK8中日期類(lèi)型該如何使用詳解

    深度思考JDK8中日期類(lèi)型該如何使用詳解

    這篇文章主要介紹了JDK8中日期類(lèi)型該如何使用詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • Java中快速把map轉(zhuǎn)成json格式的方法

    Java中快速把map轉(zhuǎn)成json格式的方法

    這篇文章主要介紹了Java中快速把map轉(zhuǎn)成json格式的方法,本文使用json-lib.jar中的JSONSerializer.toJSON方法實(shí)現(xiàn)快速把map轉(zhuǎn)換成json,需要的朋友可以參考下
    2015-07-07
  • java可變參數(shù)使用示例

    java可變參數(shù)使用示例

    這篇文章主要介紹了java可變參數(shù)使用示例,需要的朋友可以參考下
    2014-04-04
  • 深入淺析Spring 中的Null-Safety

    深入淺析Spring 中的Null-Safety

    Spring Framework 本身利用了上面這幾個(gè)注釋?zhuān)鼈円部梢赃\(yùn)用在任何基于Spring的Java 項(xiàng)目中,以聲明空安全api 和 空安全字段。這篇文章主要介紹了Spring 中的Null-Safety相關(guān)知識(shí) ,需要的朋友可以參考下
    2019-06-06
  • Hystrix?Turbine聚合監(jiān)控的實(shí)現(xiàn)詳解

    Hystrix?Turbine聚合監(jiān)控的實(shí)現(xiàn)詳解

    微服務(wù)架構(gòu)下,?個(gè)微服務(wù)往往部署多個(gè)實(shí)例,如果每次只能查看單個(gè)實(shí)例的監(jiān)控,就需要經(jīng)常切換很不?便,在這樣的場(chǎng)景下,我們可以使??Hystrix?Turbine?進(jìn)?聚合監(jiān)控,它可以把相關(guān)微服務(wù)的監(jiān)控?cái)?shù)據(jù)聚合在?起,便于查看
    2022-09-09
  • Ubuntu16.04安裝部署solr7的圖文詳細(xì)教程

    Ubuntu16.04安裝部署solr7的圖文詳細(xì)教程

    這篇文章主要為大家詳細(xì)介紹了Ubuntu16.04安裝部署solr7的圖文詳細(xì)教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-07-07
  • 詳解java 中泛型中的類(lèi)型擦除和橋方法

    詳解java 中泛型中的類(lèi)型擦除和橋方法

    這篇文章主要介紹了詳解java 中泛型中的類(lèi)型擦除和橋方法的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • java 基本類(lèi)型,數(shù)組,方法實(shí)例詳解

    java 基本類(lèi)型,數(shù)組,方法實(shí)例詳解

    文章介紹Java的8種基本數(shù)據(jù)類(lèi)型,包括整數(shù)類(lèi)型(byte、short、int、long)、浮點(diǎn)類(lèi)型(float、double)、字符類(lèi)型(char)和布爾類(lèi)型(boolean),每種類(lèi)型都有其占用內(nèi)存、取值范圍、默認(rèn)值和使用要點(diǎn),文章涵蓋了類(lèi)型轉(zhuǎn)換和數(shù)組的基本概念,感興趣的朋友跟隨小編一起看看吧
    2026-02-02
  • Java ResourceBundle案例詳解

    Java ResourceBundle案例詳解

    這篇文章主要介紹了Java ResourceBundle案例詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08

最新評(píng)論

高尔夫| 大英县| 兰溪市| 大石桥市| 汉川市| 罗田县| 体育| 剑阁县| 即墨市| 利津县| 炉霍县| 瓦房店市| 衡南县| 旌德县| 蒙山县| 赤壁市| 万州区| 安达市| 岚皋县| 临夏县| 江城| 澳门| 桦南县| 阿拉善盟| 绥江县| 都兰县| 光泽县| 平凉市| 大丰市| 彭州市| 盖州市| 道真| 灌云县| 大田县| 沁阳市| 宜州市| 盐源县| 肇源县| 靖西县| 志丹县| 榆中县|