SpringBoot 異步調用方法並接收返回值


一、背景  

項目中肯定會遇到異步調用其他方法的場景,比如有個計算過程,需要計算很多個指標的值,但是每個指標計算的效率快慢不同,如果采用同步執行的方式,運行這一個過程的時間是計算所有指標的時間之和。比如:

  方法A:計算指標x,指標y,指標z的值,其中計算指標x需要1s,計算指標y需要2s,指標z需要3s。最終執行完方法A就是5s。

  現在用異步的方式優化一下

  方法A異步調用方法B,方法C,方法D,方法B,方法C,方法D分別計算指標x,指標y,指標z的值,那么最終執行完方法A的時間則是3s。

還有一種用途是當一個業務里面需要多個請求時,這時候異步並發請求所得到的回報遠遠是物有所值的。因為他是異步執行的,話不多說,一下是在springBoot里面使用並發請求;

 

二、spring boot中異步並發使用

2.1、appllication.yml

#****************集成Async線程池開始*******************
async: # Async線程池 配置
  executor:
    corepoolsize: 20
    maxpoolsize: 25
    queuecapacity: 40
    keepaliveseconds: 200
    threadnameprefix: appasync
    awaitterminationseconds: 60
#*****************集成Async線程池結束******************

 

 

2.2、配置線程池

@Configuration
@EnableAsync
public class ExecutorConfig {

    @Value("${async.executor.corepoolsize}")
    private Integer corePoolSize;

    @Value("${async.executor.maxpoolsize}")
    private Integer maxPoolSize;

    @Value("${async.executor.queuecapacity}")
    private Integer queueCapacity;

    @Value("${async.executor.keepaliveseconds}")
    private Integer keepAliveSeconds;

    @Value("${async.executor.threadnameprefix}")
    private String threadNamePrefix;

    @Value("${async.executor.awaitterminationseconds}")
    private Integer awaitTerminationSeconds;

    /**
     * 線程池
     *
     * @return
     */
    @Bean(name = "asyncExecutor")
    public Executor asyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 基礎線程數 corePoolSize: 10
        executor.setCorePoolSize(corePoolSize);
        // 最大線程數 maxPoolSize: 15
        executor.setMaxPoolSize(maxPoolSize);
        // 隊列長度 queueCapacity: 25
        executor.setQueueCapacity(queueCapacity);
        //  線程池維護線程所允許的空閑時間,單位為秒 keepAliveSeconds: 200
        executor.setKeepAliveSeconds(keepAliveSeconds);
        // 線程名字 threadNamePrefix: appasync
        executor.setThreadNamePrefix(threadNamePrefix);
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 等待所有任務都完成再繼續銷毀其他的Bean
        executor.setWaitForTasksToCompleteOnShutdown(true);
        // 線程池中任務的等待時間,如果超過這個時候還沒有銷毀就強制銷毀,以確保應用最后能夠被關閉,而不是阻塞住
        executor.setAwaitTerminationSeconds(awaitTerminationSeconds);
        executor.initialize();
        return executor;
    }
}

 

 

2.3、線程池監控(這個可有可無,主要是為了對線程池參數及時的調優)

@RestController
@Slf4j
@RequestMapping("/pubapi/asyncExecutor")
public class AsyncExecutorController extends BaseController {

    @Resource(name = "asyncExecutor")
    private Executor asyncExecutor;

    @PostMapping("/monitor")public ResultBean<Map<String, Object>> getAsyncExecutorData() {
        ResultBean<Map<String, Object>> resultBean = ResultBeanUtil.error500();
        if (asyncExecutor == null) {
            return resultBean;
        }

        try {
            ThreadPoolTaskExecutor executorTask = (ThreadPoolTaskExecutor) asyncExecutor;
            ThreadPoolExecutor executor = executorTask.getThreadPoolExecutor();

            // 當前排隊線程數
            int queueSize = executor.getQueue().size();
            // 當前活動線程數
            int activeCount = executor.getActiveCount();
            // 執行完線程數
            long completedThreadCount = executor.getCompletedTaskCount();
            // 總線程數
            long taskCount = executor.getTaskCount();
            // 初始線程數
            int poolSize = executor.getPoolSize();
            // 核心線程數
            int corePoolSize = executor.getCorePoolSize();
            // 線程池是否終止
            boolean isTerminated = executor.isTerminated();
            // 線城池是否關閉
            boolean isShutdown = executor.isShutdown();
            // 線程空閑時間
            long keepAliveTime = executor.getKeepAliveTime(TimeUnit.MILLISECONDS);
            // 最大允許線程數
            long maximumPoolSize = executor.getMaximumPoolSize();
            // 線程池中存在的最大線程數
            long largestPoolSize = executor.getLargestPoolSize();

            Map<String, Object> threadPoolData = new HashMap<>(18);
            threadPoolData.put("當前排隊線程數", queueSize);
            threadPoolData.put("當前活動線程數", activeCount);
            threadPoolData.put("執行完線程數", completedThreadCount);
            threadPoolData.put("總線程數", taskCount);
            threadPoolData.put("初始線程數", poolSize);
            threadPoolData.put("核心線程數", corePoolSize);
            threadPoolData.put("線程池是否終止", isTerminated);
            threadPoolData.put("線城池是否關閉", isShutdown);
            threadPoolData.put("線程空閑時間", keepAliveTime);
            threadPoolData.put("最大允許線程數", maximumPoolSize);
            threadPoolData.put("線程池中存在的最大線程數", largestPoolSize);

            InetAddress inetAddress = IdWorker.getLocalHostLANAddress();
            Map<String, Object> resultData = new HashMap<>(4);
            resultData.put("ip", inetAddress.getHostAddress());
            resultData.put("threadPoolData", threadPoolData);

            resultBean = ResultBeanUtil.success("請求成功!", resultData);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultBean;
    }

}

 

 

2.4、代碼中使用

public void getMap(){
        /**
         * 先將耗時的、相互之間無依賴的操作先執行,由於其執行結果暫時不是特別關注,所以
         */
        Future<String> futureA = functionA();
        Future<String> futureB = functionB();
        /**
         * 執行其他的操作,其實functionA(),functionB()也在工作
         */
        aaa();
        /**
         * 獲取異步的結果,然后計算
         */
        try {
            String resultA =futureA.get();
            String resuleB = futureB.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        
    }

    public Future<String> functionA (){
        Future<String> future = null;
        try {
            Thread.sleep(5000);
            future = new AsyncResult<String>("functionA");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return future;
    }

    public Future<String> functionB (){
        Future<String> future = null;
        try {
            Thread.sleep(3000);
            future = new AsyncResult<String>("functionB");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return future;
    }

    public void aaa(){
        System.out.println("我是");
    }

 

 

三、使用誤區

  在使用時候,

 

四、線程池選型


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM