1、場景
http請求,業務異步處理;
1)無需返回的,比如發送短信,push消息,郵件發送等附屬業務,異步處理,減少http請求總耗時,提升客戶體驗。
2)需要返回的,前端等待業務處理結果數據,異步處理返交給http請求的主線程,返回前端;如果是單個業務此處可以優化,請查看此博文前一篇和後一篇;如果是多個業務處理,可以使用多個有返回的異步處理,總重彙總結果並返回。
2、知識點
1)線程池ThreadPoolTaskExecutor
2)註解:@EnableAsync,@Async("asyncServiceExecutor")
3)返回值封裝Future<T>,new AsyncResult<>(T)
3、代碼示例
1)controller
package com.liuxd.controller;
import com.liuxd.entity.Responses;
import com.liuxd.service.TaskService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.Future;
@Slf4j
@RestController
public class AsyncCtr {
@Autowired
private TaskService taskService;
@RequestMapping(value = "/get", method = RequestMethod.GET)
public Responses<String> getResult() throws Exception {
log.info("收到HTTP請求...");
long startTime = System.currentTimeMillis();
//1.異步執行_處理數據_無需等待
taskService.handleData();
//2.異步執行_處理數據_等待處理結果
Future<String> future = taskService.getData();
String result = future.get();
log.info("接收HTTP請求線程任務已完成,退出!");
long endTime = System.currentTimeMillis();
log.info("http請求總耗時: " + (endTime - startTime) + "ms");
return new Responses<>(0, result, "SUCCESS");
}
}
2)service
package com.liuxd.service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import java.util.concurrent.Future;
@Slf4j
@Service
public class TaskService {
@Async("asyncServiceExecutor")
public void handleData() {
log.info("調用service無返回異步方法,開始執行...");
long startTime = System.currentTimeMillis();
try {
Thread.sleep(2500L);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("調用service無返回異步方法,執行結束!!");
long endTime = System.currentTimeMillis();
log.info("調用service無返回異步方法總耗時: " + (endTime - startTime) + "ms");
}
@Async("asyncServiceExecutor")
public Future<String> getData(){
log.info("調用service有返回異步方法,開始執行...");
long startTime = System.currentTimeMillis();
try {
Thread.sleep(2500L);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("調用service有返回異步方法,執行結束!!");
long endTime = System.currentTimeMillis();
log.info("調用service有返回異步方法總耗時: " + (endTime - startTime) + "ms");
return new AsyncResult<>("異步處理完成!");
}
}
3)線程池
package com.liuxd.config;
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;
/**
* @program: unif-insure-service
* @description: 線程池
**/
@Configuration
@EnableAsync
public class ExecutorConfig {
@Bean
public Executor asyncServiceExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//配置核心線程數
executor.setCorePoolSize(5);
//配置最大線程數
executor.setMaxPoolSize(5);
//配置隊列大小
executor.setQueueCapacity(1000);
//配置線程池中的線程的名稱前綴
executor.setThreadNamePrefix("async-system-");
// rejection-policy:當pool已經達到max size的時候,如何處理新任務
// CALLER_RUNS:不在新線程中執行任務,而是有調用者所在的線程來執行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//執行初始化
executor.initialize();
return executor;
}
}
4)Responses
package com.liuxd.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Responses<T> {
private Integer code;
private String msg;
private T data;
}
5)打印結果
6)結果分析
1) 共三個線程,http請求主線程,異步無返回線程,異步有返回線程
2)主線程不需要等待無返回線程,會等待有返回線程結果,並最終返回