參考連結: https://blog.csdn.net/le_17_4_6/article/details/118699111
程式碼案例
多執行緒工具類 提高執行執行緒和獲取返回資料方法
/** * 多執行緒工具類 */ public class ConcurrentUtil { /** * 執行任務 * * @param <ResponseModel> 返回的結果集Future ResponseModel * @param executorService ExecutorService * @param callable 回撥 * @return Future ResponseModel */ public static <ResponseModel> Future<ResponseModel> doJob(ExecutorService executorService, MyCallable callable) { return (Future<ResponseModel>) executorService.submit(callable); } /** * 獲取結果集,執行時會阻塞直到有結果,中間的異常不會被靜默 * * @param future Future * @param <ResponseModel> 返回的結果集 ResponseModel * @return ResponseModel */ public static <ResponseModel> ResponseModel futureGet(Future<ResponseModel> future) { try { return future.get(); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); throw new RuntimeException(e.getMessage()); } } }
公共類
/** * 響應結果類 */ @Data @ToString public class ResponseModel implements Serializable { //訊息 private String message; //狀態碼 private int messageCode; //結果 private Object result; public ResponseModel(String message, int messageCode, Object result) { this.message = message; this.messageCode = messageCode; this.result = result; } public ResponseModel() { } }
public final class StFlag { public StFlag() { } /** * 性別:0-男,1-女 */ public static final String SEX_FLAG_0 = "0"; public static final String SEX_FLAG_1 = "1"; /** * 學生服務 */ public static final String STUDENT_SERVICE = "STUDENT"; /** * 問卷服務 */ public static final String QUESTION_SERVICE = "QUESTION"; }
/** * 多執行緒業務類 */ @Slf4j @Setter public class MyCallable implements Serializable, Callable<ResponseModel> { //服務名 private String whichServiceName; private StudentController studentController; private RequestStudentModel studentEntity; public MyCallable(String whichServiceName, StudentController studentController, RequestStudentModel studentEntity) { this.whichServiceName = whichServiceName; this.studentController = studentController; this.studentEntity = studentEntity; } @Override public ResponseModel call(){ if (StFlag.STUDENT_SERVICE.equalsIgnoreCase(whichServiceName)){ return studentController.getStudentList(studentEntity); } return studentController.getStudentList(studentEntity); } }
/** * 學生相關控制器,真正業務類,具體業務了邏輯自己實現 */ @RestController @RequestMapping("/student") @Slf4j public class StudentController { @Autowired private StudentService studentService; /** * 查詢問卷校驗項 * @return */ @PostMapping("/getStudentList") public ResponseModel getStudentList(@RequestBody RequestStudentModel studentEntity){ try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } return new ResponseModel("查詢成功", 200, ""); } }
測試主類
特別注意, ConcurrentUtil.futureGet(responseRqestionFuture);方法要在所有執行緒執行完之後執行,否則達不到多執行緒執行的效果,因為future.get()會阻塞,知道拿到返回值
/** * 多執行緒控制器 */ @RestController @RequestMapping("/concurrent") @Slf4j public class CurrentController { @Autowired private StudentController studentController; /** * 多執行緒測試 * @return */ @PostMapping("/current") public ResponseModel getStudentList(@RequestBody RequestStudentModel studentEntity) throws ExecutionException, InterruptedException { log.info("current ---- start "); List list = new ArrayList(); ExecutorService executorService = new ThreadPoolExecutor(2, 2, 3, TimeUnit.SECONDS, new LinkedBlockingQueue<>(30), Executors.defaultThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy()); // 另一種方式建立執行緒池,不推薦,因為不能修改內部引數,比如佇列型別 // ExecutorService executorService = Executors.newFixedThreadPool(20); // 多執行緒呼叫方式 // MyCallable myCallable= new MyCallable(StFlag.STUDENT_SERVICE,studentController, studentEntity); // Future<ResponseModel> submit = executorService.submit(myCallable); // ResponseModel responseModel1 = submit.get(); long timeStart = System.currentTimeMillis(); // 查詢問卷 Future<ResponseModel> responseRqestionFuture = ConcurrentUtil.doJob(executorService, new MyCallable(StFlag.STUDENT_SERVICE,studentController, studentEntity)); // 查詢學生 Future<ResponseModel> responseSudentFuture = ConcurrentUtil.doJob(executorService, new MyCallable(StFlag.QUESTION_SERVICE,studentController, studentEntity)); //future.get方法 //執行緒池執行緒是非同步提交的,但是返回分頁結果是需要同步返回,Future的get是個阻塞方法。 // 只有所有的任務全部完成,我們才能用get按照任務的提交順序依次返回結果, // 呼叫future.get()方法檢視執行緒池內所有方法是否已執行完成,達到執行緒非同步提交,結果集同步返回的效果。 ResponseModel myCallableResponseModel1 = ConcurrentUtil.futureGet(responseRqestionFuture); ResponseModel myCallableResponseModel2 = ConcurrentUtil.futureGet(responseSudentFuture); long timeMiddle = System.currentTimeMillis(); long longMutiThread = timeMiddle - timeStart; log.info("多執行緒執行用時為: {}", longMutiThread); list.add("多執行緒執行用時為: "+longMutiThread); // 單執行緒查詢 ResponseModel responseModel = studentController.getStudentList(studentEntity); ResponseModel studentList = studentController.getStudentList(studentEntity); long timeEnd = System.currentTimeMillis(); long longDingleThread = timeEnd - timeMiddle; log.info("單執行緒執行用時為: {}", longDingleThread); list.add("單執行緒執行用時為: "+longDingleThread); list.add(myCallableResponseModel1); list.add(myCallableResponseModel2); list.add(responseModel); list.add(studentList); log.info("current ---- end "); return new ResponseModel("多執行緒測試完成", 200, list); } }
測試案例
POSTMan測試
控制檯列印
2022-07-02 01:48:37.521 INFO current ---- start 【http-nio-8081-exec-2】【CurrentController:34】 2022-07-02 01:48:39.552 INFO 多執行緒執行用時為: 2144 【http-nio-8081-exec-2】【CurrentController:60】 2022-07-02 01:48:43.588 INFO 單執行緒執行用時為: 4028 【http-nio-8081-exec-2】【CurrentController:67】 2022-07-02 01:48:43.589 INFO current ---- end 【http-nio-8081-exec-2】【CurrentController:73】