多執行緒查詢,效率翻倍

hikoukay 發表於 2022-07-02

參考連結: 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:342022-07-02 01:48:39.552 INFO  多執行緒執行用時為: 2144 【http-nio-8081-exec-2】【CurrentController:602022-07-02 01:48:43.588 INFO  單執行緒執行用時為: 4028 【http-nio-8081-exec-2】【CurrentController:672022-07-02 01:48:43.589 INFO  current   ---- end  【http-nio-8081-exec-2】【CurrentController:73】