参考链接: 查询速度起飞之Java利用多线程进行并发数据查询_衡与墨的博客-CSDN博客_多线程并发查询数据库
代码案例
多线程工具类 提高执行线程和获取返回数据方法
/**
* 多线程工具类
*/
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】