異步獲取返回值(@Async註解 和 線程池提交 callable 兩種方式)

這裏介紹兩種 通過異步獲取返回值的兩種操作,這裏做個小記。

1、定義示範的接口

public interface SycService {
    JsonVO testSyc();
    JsonVO testSyc2();
}

2、定義實現的實現類

@Service
public class SycServiceImpl implements SycService {

    private static Logger logger = LoggerFactory.getLogger(SycServiceImpl.class);

    /**
     * 通過線程池提交 callable 實現異步
     * @return
     */
    @Override
    public JsonVO testSyc() {

        logger.error("----------通過線程池提交 callable 實現異步");
        ExecutorService exceutor = (ThreadPoolExecutor)Executors.newCachedThreadPool();
        List<Future<String>> list = new ArrayList<>(5);
        for (int i = 0; i < 5; i++) {
            Future<String> future = exceutor.submit(new ThreadPoolTask(i + "test"));
            list.add(future);
        }
        List<String> resultLst = new ArrayList<>();
        for (Future<String> future : list) {
            try {
                String str = future.get(10,TimeUnit.SECONDS);
                resultLst.add(str);
            } catch (Exception e) {
                logger.error("test Syc has error:{}", e);
            }
        }
        exceutor.shutdown();
        System.out.println("註解線程池submit獲取:" + resultLst);
        return new JsonVO(200,"success",resultLst);

    }

    /**
     * 定義內部類 用於  線程池提交callable
     */
    class ThreadPoolTask implements Callable<String>{
        private String param;

        public ThreadPoolTask(String param) {
            this.param = param;
        }

        @Override
        public String call()  {
            try {
                System.out.println("callable 獲取參數 :" + param);
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return param + "--callable:123";
        }
    }

    
    
    
    @Autowired
    private AnnotationTask annotationTask;

    /**
     * 通過註解@Async 實現異步
     * @return
     */
    @Override
    public JsonVO testSyc2() {

        logger.error("----------通過註解@Async  實現異步");
        List<String> resultLst = new ArrayList<>();
        try {
        CountDownLatch countDownLatch = new CountDownLatch(5);

        for (int i = 0; i < 5; i++) {
             annotationTask.testAnnotation(i + "test",resultLst, countDownLatch);

        }

            countDownLatch.await(10, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
            logger.error("test Syc2 has error:{}", e);
        }

        System.out.println("註解@Async獲取:"+resultLst);
        return new JsonVO(200,"success",resultLst);

    }


}


3、定義 @Async註解 方式 需要的異步類,這裏需要注意的是這裏的異步是通過@Async的方式,如果請求太多,會一直創建線程。如果需要控制線程,可以對這個異步任務定義線程池的方式。
如果需要通過線程池對請求數進行限制可以參考:
https://blog.csdn.net/fajing_feiyue/article/details/101037662

@EnableAsync
@Component
public class AnnotationTask {

    @Async
    public void testAnnotation(String str, List<String> resultLst, CountDownLatch countDownLatch) {

        try {
            System.out.println("annotation 獲取參數 :" + str);
            TimeUnit.SECONDS.sleep(1);
            resultLst.add(str + "--annotation:123");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            countDownLatch.countDown();
        }

    }
}

4、測試

   private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    @Autowired
    private SycService sycService;


    @Test
    public void TestSyc(){
        System.out.println("testSyc time start:"+formatter.format(LocalDateTime.now()));
        JsonVO jsonVO = sycService.testSyc();
        System.out.println("--------------testSyc----------- time:"+formatter.format(LocalDateTime.now()));
        System.out.println(jsonVO);
        JsonVO jsonVO2 = sycService.testSyc2();
        System.out.println("--------------testSyc2-----------time:"+formatter.format(LocalDateTime.now()));
        System.out.println(jsonVO2);
    }

測試結果:

[2020-02-22 15:53:10:539] | [ERROR] [main] [com.yin.dynamic_elasticjob.service.impl.SycServiceImpl] [29] -| ----------通過線程池提交 callable 實現異步
callable 獲取參數 :2test
callable 獲取參數 :1test
callable 獲取參數 :3test
callable 獲取參數 :0test
callable 獲取參數 :4test
註解線程池submit獲取:[0test--callable:123, 1test--callable:123, 2test--callable:123, 3test--callable:123, 4test--callable:123]
--------------testSyc----------- time:2020-02-22 15:53:11
JsonVO(statusCode=200, errorMessage=success, data=[0test--callable:123, 1test--callable:123, 2test--callable:123, 3test--callable:123, 4test--callable:123])
[2020-02-22 15:53:11:559] | [ERROR] [main] [com.yin.dynamic_elasticjob.service.impl.SycServiceImpl] [75] -| ----------通過註解@Async實現異步
annotation 獲取參數 :0test
annotation 獲取參數 :3test
annotation 獲取參數 :4test
annotation 獲取參數 :1test
annotation 獲取參數 :2test
註解@Async獲取:[0test--annotation:123, 4test--annotation:123, 1test--annotation:123, 3test--annotation:123, 2test--annotation:123]
--------------testSyc2-----------time:2020-02-22 15:53:12
JsonVO(statusCode=200, errorMessage=success, data=[0test--annotation:123, 4test--annotation:123, 1test--annotation:123, 3test--annotation:123, 2test--annotation:123])

可以看到兩種方式都獲取到想要的結果,在這次示範兩次獲取數據都控制獲取到數據的返回時間。線程池提交 callable 的這種方式 每個請求都有頻繁創建線程池,@Async 註解的方式,一直是使用的一個線程池,對性能會相對好一點。兩種方式 都沒有對示範創建的線程限制,可能創建的線程使用飆升,對cpu負載過高。如果有必要刻意通過配置總的線程池對其限制,防止無限創建線程。

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