平时项目开发中,接口业务逻辑复杂,sql也没有了优化空间,这时我们就可以用到多线程来并行处理,提升接口效率,这里做个记录
使用场景
-
定时任务批量处理数据
-
复杂逻辑需要同时满足多个条件判断
-
MQ消费
-
日志异步记录
多线程使用我归为两类
- 多线程无返回值
- 多线程有返回值
一、有返回值多线程实现
封装一个通用工具类AsyncThreadUtils
public class AsyncThreadUtils {
private static final int corePoolSize = Runtime.getRuntime().availableProcessors();//CPU核心数
private static final int maximumPoolSize = corePoolSize * 2;
private static long keepAliveTime = 1;
private static TimeUnit keepAliveTimeUnit = TimeUnit.MINUTES;
private static BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(1024);
private static RejectedExecutionHandler rejectedHandler = new ThreadPoolExecutor.CallerRunsPolicy();
/**
* corePoolSize : 线程池核心线程数,最好默认CPU核心数
* maximumPoolSize : 线程池最大线程数,最好是核心线程数的两倍,太多会引起线程切换
* keepAliveTime : 大于核心线程数的空闲线程存活时间
* keepAliveTimeUnit : 空闲线程存活时间的单位(秒、分钟、小时等等)
* workQueue : 线程池有界队列,新任务没有可用线程处理时会把任务放到该队列中,等待被处理
* rejectedHandler : 拒绝处理策略,默认直接丢弃并抛出异常-AbortPolicy,调用者线程直接处理-CallerRunsPolicy
*/
private static ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(
corePoolSize,
maximumPoolSize,
keepAliveTime,
keepAliveTimeUnit,
workQueue,
rejectedHandler
);
/**
* 直接提交任务,无返回值
* @param task
*/
public static void submit(Runnable task){
poolExecutor.submit(task);
}
/**
* 提交任务,返回泛型结果
* @param task
* @param <T>
* @return
*/
public static <T> Future<T> submit(Callable<T> task){
return poolExecutor.submit(task);
}
}
Controller层测试多线程
@RestController
@RequestMapping(value = "/threadPool")
public class ThreadPoolController {
private static final Log LOG = LogFactory.getLog(ThreadPoolController.class);
@ApiOperation("测试多线程并发处理")
@RequestMapping(value = "/ceshiThread")
public ResultMsg ceshiThread(){
try {
int finalI = 0;
for (int i = 0; i < 20; i++) {
finalI ++;
int finalI1 = finalI;
AsyncThreadUtils.submit(() -> c(finalI1));
}
} catch (Exception e) {
e.printStackTrace();
}
return ResultUtil.success(null);
}
@ApiOperation("测试多线程异步处理")
@RequestMapping(value = "/ceshiAsync")
public ResultMsg ceshiAsync(){
int a = 1;
try {
long currentTimeMillis = System.currentTimeMillis();
a();
b();
long currentTimeMillis1 = System.currentTimeMillis();
LOG.error("同步耗时:"+ (currentTimeMillis1 - currentTimeMillis));
long currentTimeMillis2 = System.currentTimeMillis();
Future<Boolean> submit = AsyncThreadUtils.submit(() -> a());
Future<Boolean> submit2 = AsyncThreadUtils.submit(() -> b());
Boolean aBoolean = submit.get();
Boolean aBoolean2 = submit2.get();
long currentTimeMillis3 = System.currentTimeMillis();
LOG.error("异步耗时:"+ (currentTimeMillis3 - currentTimeMillis2));
} catch (Exception e) {
e.printStackTrace();
}
return ResultUtil.success(null);
}
private Boolean a(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return false;
}
private Boolean b(){
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return false;
}
private Boolean c(int count){
try {
Thread.sleep(5000);
LOG.error("打印:"+ count);
} catch (InterruptedException e) {
e.printStackTrace();
}
return false;
}
}
二、实现有返回值多线程
package com.deppon.cc.service.impl;
import java.util.concurrent.*;
public class CallableExample {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 创建一个ExecutorService,这里使用固定大小的线程池
ExecutorService executor = Executors.newFixedThreadPool(2);
// 提交Callable任务给ExecutorService
Future<String> future = executor.submit(new MyCallable());
Future<String> future1 = executor.submit(new MyCallable1());
// 在任务完成之前,主线程可以做其他事情
// 获取Callable的返回值
String result = future.get(); // 这会阻塞,直到任务完成
String result1 = future1.get();
// 关闭ExecutorService
executor.shutdown();
}
static class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
// 模拟耗时的计算
Thread.sleep(2000);
return "Hello from Callable!";
}
}
static class MyCallable1 implements Callable<String> {
@Override
public String call() throws Exception {
// 模拟耗时的计算
Thread.sleep(2000);
return "Hello from Callable!";
}
}
}
多线程并行处理任务可以提升服务器资源使用率,同时可以提高接口响应效率,值得推荐!!!