Spring Async多線程使用

本文記錄Spring Async對Java多線程的支持


使用場景

Java在處理多線程時需要用到線程池及其相關的API,配置較爲零散,學習成本較高.Spring提供了便捷的配置類來支持多線程的實現.

技術點

  • Java多線程
  • Spring Async

Spring Async配置類

import org.springframework.context.annotation.Bean;
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;

/**
 * 開啓多線程操作,註解方式
 * 在需要進行異步處理的方法上加上@Async註解
 */
@Configuration
@EnableAsync
public class AsyncConfig {

    /**
     * 設置線程池基本大小值, 線程池維護線程的最少數量
     */
    private int corePoolSize = 10;
    /**
     * 設置線程池最大值
     */
    private int maxPoolSize = 200;
    /**
     * 線程池所使用的緩衝隊列大小
     */
    private int queueCapacity = 1024;
    /**
     * 配置線程最大空閒時間
     */
    private int keepAliveSeconds = 50000;

    @Bean
    public Executor asyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(corePoolSize);
        executor.setMaxPoolSize(maxPoolSize);
        executor.setQueueCapacity(queueCapacity);
        executor.setKeepAliveSeconds(keepAliveSeconds);
        executor.setThreadNamePrefix("AsyncExecutor-");

        /*
         * rejection-policy:當pool已經達到max size的時候,如何處理新任務
         * CALLER_RUNS:不在新線程中執行任務,而是由調用者所在的線程來執行
         */
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
}


Spring Async服務類-控制層

import org.eureka.service.impl.AsyncService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

/**
 * Description: 異步任務測試類
 */
@RestController
public class AsyncController {
    @Autowired
    private AsyncService asyncService;
 
    @RequestMapping(value = "/hello",method = RequestMethod.GET)
    public String testAsyncNoRetrun(){
        long start = System.currentTimeMillis();
         asyncService.doNoReturn();
         return String.format("任務執行成功,耗時{%s}", System.currentTimeMillis() - start);
    }

    @GetMapping("/hi")
    public Map<String, Object> testAsyncReturn() throws ExecutionException, InterruptedException {
        long start = System.currentTimeMillis();

        Map<String, Object> map = new HashMap<>();
        List<Future<String>> futures = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            Future<String> future = asyncService.doReturn(i);
            futures.add(future);
        }
        /*
         * 讀取的時候,記得要批量讀取不能單獨讀取,否則無法實現異步的效果
         * 且需要注意:
         * 異步方法調用一定需要通過Spring代理,@Async和@Transactional註解類似,只有在代理模式下生效
         */
        List<String> response = new ArrayList<>();
        for (Future future : futures) {
            String string = (String) future.get();
            response.add(string);
        }
        map.put("data", response);
        map.put("消耗時間", String.format("任務執行成功,耗時{%s}毫秒", System.currentTimeMillis() - start));
        return map;
    }
}


Spring Async服務類-實現層

import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.concurrent.Future;

/**
 * Description: 異步任務測試類
 */
@Service
public class AsyncService {

    /**
     * TODO 處理無返回的異步任務
     * @param
     * @return void
     * @throws
     * @date 2019/8/20 16:34
     **/
    @Async
    public void doNoReturn(){
        try {
            // 這個方法執行需要三秒
            Thread.sleep(3000);
            System.out.println("方法執行結束" + new Date());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * TODO 處理有返回的異步任務
     * @param i
     * @return java.util.concurrent.Future<java.lang.String>
     * @throws
     * @date 2019/8/20 16:35
     **/
    @Async
    public Future<String> doReturn(int i){
        try {
            // 這個方法需要調用500毫秒
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 消息彙總
        return new AsyncResult<>(String.format("這個是第{%s}個異步調用的證書", i));
    }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章