SpringBoot实现多线程
多线程方式一:实现AsyncConfigurer 接口
配置类实现接口AsyncConfigurer,返回一个ThreadPoolTaskExecutor 线程池对象。
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
// ThredPoolTaskExcutor的处理流程
// 当池子大小小于corePoolSize,就新建线程,并处理请求
// 当池子大小等于corePoolSize,把请求放入workQueue中,池子里的空闲线程就去workQueue中取任务并处理
// 当workQueue放不下任务时,就新建线程入池,并处理请求,如果池子大小撑到了maximumPoolSize,就用RejectedExecutionHandler来做拒绝处理
// 当池子的线程数大于corePoolSize时,多余的线程会等待keepAliveTime长时间,如果无请求可处理就自行销毁
@Override
@Bean
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程数:线程池创建的时候初始化的线程数
executor.setCorePoolSize(10);
// 最大线程数:线程池最大的线程数,只有缓冲队列满了之后才会申请超过核心线程数的线程
executor.setMaxPoolSize(100);
// 缓冲队列:用来缓冲执行任务的队列
executor.setQueueCapacity(50);
// 线程池关闭:等待所有任务都完成再关闭
executor.setWaitForTasksToCompleteOnShutdown(true);
// 等待时间:等待5秒后强制停止
executor.setAwaitTerminationSeconds(5);
// 允许空闲时间:超过核心线程之外的线程到达60秒后会被销毁
executor.setKeepAliveSeconds(60);
// 线程名称前缀
executor.setThreadNamePrefix("learn-Async-");
// 初始化线程
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return null;
}
}
通过@Async注解表明该方法是异步方法,如果注解在类上,那表明这个类里面的所有方法都是异步的。
@Service
public class AsyncService {
@Async // 表明该方法是异步方法。如果注解在类上,那表明类里面的所有方法都是异步
public void executeAsyncTask(int i) {
System.out.println("线程" + Thread.currentThread().getName() + " 执行异步任务:" + i);
}
}
多线程方式二:配置 java.util.concurrent.TaskExecutor
新增一个配置类,默认情况下使用 SimpleAsyncTaskExecutor
@Configuration
@EnableAsync //启用异步任务
public class ThreadConfig {
@Bean("asyncServiceExecutor")
public ThreadPoolTaskExecutor executor(){
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//配置核心线程数
executor.setCorePoolSize(15);
//配置最大线程数
executor.setMaxPoolSize(30);
//配置队列大小
executor.setQueueCapacity(1000);
//线程的名称前缀
executor.setThreadNamePrefix("Executor-");
//线程活跃时间(秒)
//executor.setKeepAliveSeconds(60);
//等待所有任务结束后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
//设置拒绝策略
//executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//执行初始化
executor.initialize();
return executor;
}
}
使用线程池:可以使用@Async注解或者直接调用TaskExecutor的submit或者execute方法提交任务。
//-----------------------接口类--------------------------
public interface UserService{
/**
* 执行异步任务
*/
void writeText();
}
//-----------------------接口实现类----------------------
@Service
public class UserServiceImpl implement UserService{
private static Logger logger = LogManager.getLogger(AsyncServiceImpl.class.getName());
@Async("asyncServiceExecutor")
@Over
public void writeTxt(String fileName){
logger.info("线程-" + Thread.currentThread().getId() + "在执行写入");
try {
File file = new File(fileName);
List<String> lines = FileUtils.readLines(file);
File copyFile = new File(fileName + "_copy.txt");
lines.stream().forEach(string->{
try {
FileUtils.writeStringToFile(copyFile,string,"utf8",true);
FileUtils.writeStringToFile(copyFile,"\r\n","utf8",true);
} catch (IOException e) {
logger.info(e.getMessage());
}
});
}catch (Exception e) {
logger.info(e.getMessage());
}
}
}
//-----------------------测试----------------------------
@RunWith(SpringRunner.class)
@SpringBootTest
public class BootApplicationTests {
@Autowired
private AsyncService asyncService;
@Test
public void write() {
File file = new File("F://ac_code_1//test.txt");
try {
FileUtils.writeStringToFile(file, "ceshi", "utf8");
FileUtils.writeStringToFile(file, "\r\n", "utf8");
FileUtils.writeStringToFile(file, "ceshi2", "utf8");
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Async原理
本质上Async注解的实现依赖于动态代理,代理过程中将任务提交给线程池,存在以下流程:
如上图所示,Spring为使用Async注解Bean对象生产一个动态代理对象,当Async注解的方法被调用时,会进入代理流程,选择线程池、封装调用逻辑并提交给线程池执行,返回执行结果。
注意:未被@Async注解的方法则不会执行上述流程(static方法也不会)
由于异步的本质是基于代理实现,所以同一个类中的方法调用会导致被调用方的异步作用失效,该场景与Spring的事务失效原因相同。
注解@Async失效的情况
- 注解@Async的方法不是public方法
- 注解@Async的返回值只能为void或Future
- 注解@Async方法使用static修饰也会失效
- spring无法扫描到异步类,没加注解@Async或@EnableAsync注解
- 调用方与被调用方不能在同一个类(因为没走代理)
- 类中需要使用@Autowired或@Resource等注解自动注入,不能自己手动new对象
- 在Async方法上标注@Transactional是没用的,但在Async方法调用的方法上标注@Transcational是有效的
标签:
SpringBoot
, 异步
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
2022-02-12 倒排索引原理
2022-02-12 Elasticsearch索引与mapping映射
2022-02-12 ElasticSearch基本概念及索引过程
2022-02-12 【Windows】Elasticsearch单机和集群部署
2022-02-12 IntelliJ IDEA 快捷键大全(Windows)
2022-02-12 深入理解Netty编解码、粘包拆包、心跳机制