直接上代码:
第一步:配置
java
package com.testweb.testweb.threadWeb;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* User:Json
* Date: 2025/12/6
**/
@Configuration
@EnableAsync //没有这个注解 线程不会生效
@Slf4j
public class ThreadConfig implements AsyncConfigurer {
//4 核 CPU / 小型服务器配置 按服务器配置 调整
private static final int corePoolSize = 4; // 核心线程数(默认线程数)创建后会在内存里常驻
private static final int maxPoolSize = 8; // 最大线程数(包含核心线程),当核心线程和队列满时,最多会创建 4 个非核心线程
private static final int keepAliveTime = 60; // 非核心线程空闲回收时间(单位:秒)
private static final int queueCapacity = 100; // 缓冲队列数
/**
* 默认异步线程池 ThreadPoolTaskExecutor 常用
*/
@Bean("taskExecutor")
public ThreadPoolTaskExecutor taskExecutor(){
ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor();
pool.setThreadNamePrefix("DY-Async-Task-"); //线程前缀 便于日志查看
pool.setCorePoolSize(corePoolSize);
pool.setMaxPoolSize(maxPoolSize);
pool.setKeepAliveSeconds(keepAliveTime);
pool.setQueueCapacity(queueCapacity);
// pool.setAllowCoreThreadTimeOut(true);// 默认核心线程常驻 如果希望在低配服务器核心线程空闲也释放资源,可加上这行
// 直接在execute方法的调用线程中运行
pool.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 初始化
pool.initialize();
return pool;
}
/**
* 异步任务异常处理 如果调用的地方 try catch了 这边就不会走了
*/
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return (ex, method, params) -> {
log.info("异步任务出现异常: 方法: {}, 参数: {}", method.getName(), params, ex);
};
}
}
第二步: 写demo
java
package com.testweb.testweb.threadWeb;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.concurrent.CompletableFuture;
/**
* User:Json
* Date: 2025/12/6
**/
@Service
@Slf4j
public class ThreadService {
//无返回值
@Async("taskExecutor")
public void test() {
//异常 测试
// int a=1/0;
log.info("异步线程");
}
//有返回值
@Async("taskExecutor")
public CompletableFuture<Integer> asyncCompute(int num) {
log.info("异步计算开始,线程: {}", Thread.currentThread().getName());
int result = 10 / num; // 如果 num=0,会抛异常
log.info("异步计算结束,结果: {}", result);
//休息10秒 假装堵塞
try {
Thread.sleep(10 * 1000L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return CompletableFuture.completedFuture(result);
}
}
第三步:控制器测试:
kotlin
package com.testweb.testweb.threadWeb;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.CompletableFuture;
/**
* User:Json
* Date: 2025/12/6
**/
@RestController
@Slf4j
public class ThreadController {
@Autowired
ThreadService threadService;
//无返回值测试
@GetMapping("testThread")
public void test() {
threadService.test();
}
//有返回值测试
@GetMapping("/compute")
public String testCompute(@RequestParam int num) {
CompletableFuture<Integer> future = threadService.asyncCompute(num);
//1. 阻塞情况
// try {
// Integer result = future.get(); // 会阻塞,等待返回值
// log.info("阻塞 计算结果: " + result);
// } catch (Exception e) {
// log.info("异步计算异常: {}", e.getMessage(), e);
// }
// 2. 不阻塞情况 ,注册回调处理结果
future.thenAccept(result -> {
log.info("异步计算完成,不阻塞结果: {}", result);
}).exceptionally(ex -> {
log.info("异步计算异常", ex);
return null;
});
return "success";
}
}
jvm调试测试结果:


在异步方法里写业务逻辑的注意项:

如需补充,欢迎大家留言~