SpringBoot使用多线程 @EnableAsync @Async

 

我们在使用多线程的时候,往往需要创建Thread类,或者实现Runnable接口,如果要使用到线程池,我们还需要来创建Executors,在使用spring中,已经给我们做了很好的支持。只要要@EnableAsync就可以使用多线程。使用@Async就可以定义一个线程任务。通过spring给我们提供的ThreadPoolTaskExecutor就可以使用线程池。下面举个例子来说明

 

首先定义配置类

[java] view plain copy

 

  1. package com.hy.spring.test7;  
  2.   
  3. import java.util.concurrent.Executor;  
  4.   
  5. import org.springframework.context.annotation.Bean;  
  6. import org.springframework.context.annotation.ComponentScan;  
  7. import org.springframework.context.annotation.Configuration;  
  8. import org.springframework.scheduling.annotation.EnableAsync;  
  9. import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;  
  10.   
  11. @Configuration  
  12. @ComponentScan("com.hy.spring.test7")  
  13. @EnableAsync  // 启用异步任务  
  14. public class ThreadConfig  {  
  15.   
  16.      // 执行需要依赖线程池,这里就来配置一个线程池  
  17.      @Bean  
  18.      public Executor getExecutor() {  
  19.           ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();  
  20.           executor.setCorePoolSize(5);  
  21.           executor.setMaxPoolSize(10);  
  22.           executor.setQueueCapacity(25);  
  23.           executor.initialize();  
  24.           return executor;  
  25.      }  
  26. }  

 

 

定义要执行的任务

 

[java] view plain copy

 

  1. package com.hy.spring.test7;  
  2.   
  3. import java.util.Random;  
  4. import java.util.UUID;  
  5.   
  6. import org.springframework.scheduling.annotation.Async;  
  7. import org.springframework.stereotype.Service;  
  8.   
  9. @Service  
  10. public class AsynTaskService {  
  11.   
  12.      @Async    // 这里进行标注为异步任务,在执行此方法的时候,会单独开启线程来执行  
  13.      public void f1() {  
  14.           System.out.println("f1 : " + Thread.currentThread().getName() + "   " + UUID.randomUUID().toString());  
  15.           try {  
  16.               Thread.sleep(new Random().nextInt(100));  
  17.           } catch (InterruptedException e) {  
  18.               e.printStackTrace();  
  19.           }  
  20.      }  
  21.   
  22.      @Async  
  23.      public void f2() {  
  24.           System.out.println("f2 : " + Thread.currentThread().getName() + "   " + UUID.randomUUID().toString());  
  25.           try {  
  26.               Thread.sleep(100);  
  27.           } catch (InterruptedException e) {  
  28.               e.printStackTrace();  
  29.           }  
  30.      }  
  31. }  

 

 

测试类

[java] view plain copy

 

  1. package com.hy.spring.test7;  
  2.   
  3. import org.springframework.context.annotation.AnnotationConfigApplicationContext;  
  4.   
  5. public class Main {  
  6.   
  7.      public static void main(String[] args) {  
  8.           AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ThreadConfig.class);  
  9.           AsynTaskService service = context.getBean(AsynTaskService.class);  
  10.   
  11.           for (int i = 0; i < 10; i++) {  
  12.               service.f1(); // 执行异步任务  
  13.               service.f2();  
  14.           }  
  15.           context.close();  
  16.      }  
  17. }  

 

 

输出结果

 

f1 : ThreadPoolTaskExecutor-5   20e6ba88-ae51-42b9-aac6-ed399419fe6d

f2 : ThreadPoolTaskExecutor-2   0d7b1da4-e045-4d58-9054-e793f931cae1

f2 : ThreadPoolTaskExecutor-4   17b8d7c7-24e3-4bcf-b4da-822650a8f0be

f1 : ThreadPoolTaskExecutor-3   a9b32322-1c9b-4fc7-9c2a-1f7a81f2b089

f1 : ThreadPoolTaskExecutor-1   13a85fde-73c7-4c9b-9bb2-92405d1d3ac4

f2 : ThreadPoolTaskExecutor-3   8896caaf-381c-4fc3-ab0f-a42fcc25e5fd

f1 : ThreadPoolTaskExecutor-5   48246589-f8e9-4e9c-b017-8586bf14c0b0

f2 : ThreadPoolTaskExecutor-1   291b03ea-154f-46ba-bc41-69a61d1dd4d5

f1 : ThreadPoolTaskExecutor-4   856d8f48-70b4-475a-80cc-27d1635be36b

f2 : ThreadPoolTaskExecutor-2   1f7b1918-cf10-49a3-aaec-7b97a3a67e7d

f1 : ThreadPoolTaskExecutor-3   12e56d3f-d042-42dd-a387-3de80201c3b2

f2 : ThreadPoolTaskExecutor-5   bf0dbc97-61d8-4644-9ae4-4d711228198d

f1 : ThreadPoolTaskExecutor-3   4c58793a-394e-4241-87e6-fff1f480518d

f2 : ThreadPoolTaskExecutor-4   fa1d4484-d3a4-4303-9ffe-b6aaa791b157

f1 : ThreadPoolTaskExecutor-1   67144d54-d158-4c6a-865e-b80668515bea

f2 : ThreadPoolTaskExecutor-2   c48cfa18-48d4-4778-8f09-04b779338816

f1 : ThreadPoolTaskExecutor-3   30143849-3c49-4128-a811-f6468a091114

f2 : ThreadPoolTaskExecutor-5   58603271-ee4e-40c9-b6ff-199d32dfb02a

f1 : ThreadPoolTaskExecutor-1   3b0ce7ff-fdff-4e23-bb44-d1a0c1148982

f2 : ThreadPoolTaskExecutor-3   cb9a1543-955a-4bc9-b4e9-6b61188371ee

 

可以看到我们两个任务是异步进行的。

 

下面关于线程池的配置还有一种方式,就是直接实现AsyncConfigurer接口,重写getAsyncExecutor方法即可,代码如下

 

[java] view plain copy

 

  1. package com.hy.spring.test7;  
  2.   
  3. import java.util.concurrent.Executor;  
  4.   
  5. import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;  
  6. import org.springframework.context.annotation.ComponentScan;  
  7. import org.springframework.context.annotation.Configuration;  
  8. import org.springframework.scheduling.annotation.AsyncConfigurer;  
  9. import org.springframework.scheduling.annotation.EnableAsync;  
  10. import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;  
  11.   
  12. @Configuration  
  13. @ComponentScan("com.hy.spring.test7")  
  14. @EnableAsync  
  15. public class ThreadConfig implements AsyncConfigurer {  
  16.   
  17.      @Override  
  18.      public Executor getAsyncExecutor() {  
  19.           ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();  
  20.           executor.setCorePoolSize(5);  
  21.           executor.setMaxPoolSize(10);  
  22.           executor.setQueueCapacity(25);  
  23.           executor.initialize();  
  24.           return executor;  
  25.      }  
  26.   
  27.      @Override  
  28.      public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {  
  29.           return null;  
  30.      }  
  31.   
  32. }  
### Spring Boot 中使用 `@Async` 实现异步方法的最佳实践 #### 1. 开启异步功能 为了使 `@Async` 注解生效,需要在应用程序的主类或者配置类上添加 `@EnableAsync` 注解。这一步是必要的,因为只有启用该注解后,Spring 才会识别并管理带有 `@Async` 的方法。 ```java import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.EnableAsync; @SpringBootApplication @EnableAsync public class AsyncApplication { public static void main(String[] args) { SpringApplication.run(AsyncApplication.class, args); } } ``` 此部分的操作已在多个引用中提及[^2][^4]。 --- #### 2. 定义异步方法 任何希望被异步执行的方法都可以加上 `@Async` 注解。需要注意的是,默认情况下,这些方法会被放入由 Spring 创建的线程池中运行。 ```java import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; @Service public class AsyncTaskService { @Async public void executeAsyncTask() { System.out.println("任务正在异步执行..."); } @Async public Future<String> executeAsyncWithResult() throws InterruptedException { Thread.sleep(2000); // 模拟耗时操作 return new AsyncResult<>("异步返回结果"); } } ``` 上述代码展示了两种常见的场景:一种是没有返回值的任务;另一种是有返回值的任务,并且可以通过 `Future` 对象获取其结果[^3]。 --- #### 3. 自定义线程池 虽然 Spring 默认提供了一个简单的线程池用于异步任务调度,但在实际生产环境中更推荐自定义线程池以满足特定需求。可以借助 `ThreadPoolTaskExecutor` 来完成这一目标: ```java import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; @Configuration public class ThreadPoolConfig { @Bean(name = "taskExecutor") public ThreadPoolTaskExecutor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(5); // 核心线程数 executor.setMaxPoolSize(10); // 最大线程数 executor.setQueueCapacity(25); // 队列容量 executor.initialize(); // 初始化线程池 return executor; } } ``` 通过这种方式,我们可以精确控制线程的数量及其行为模式,从而优化系统的性能表现[^1]。 --- #### 4. 超时处理机制 当某些异步任务可能长时间未响应时,我们需要为其设定合理的超时策略以防阻塞资源。下面是一个基于 `CompletableFuture` 的例子展示如何实现这一点: ```java import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; public String callWithTimeout(int timeoutInSeconds) throws ExecutionException, TimeoutException, InterruptedException { CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> { try { Thread.sleep(timeoutInSeconds * 1000L); // 模拟延迟 } catch (InterruptedException e) { throw new RuntimeException(e); } return "成功"; }, taskExecutor()); return future.get(timeoutInSeconds / 2, TimeUnit.SECONDS); // 设置一半时间为超时时限 } ``` 这里利用了 Java 提供的高级 API —— `CompletableFuture` 和它的 `get(long timeout, TimeUnit unit)` 方法来简化超时逻辑的设计。 --- #### 总结 以上就是关于如何在 Spring Boot 应用程序中有效运用 `@Async` 进行异步编程的一些最佳实践建议。合理调整线程池参数以及引入适当的错误恢复手段都是构建健壮服务不可或缺的部分。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值