【多线程】@Async注解和线程池

更新时间:2023-05-05 19:14:41 阅读: 评论:0

【多线程】@Async注解和线程池
@Async注解和线程池
@Async
1.@Async是什么
Spring⾃带了⽀持任务调度和异步⽅法调⽤的注解,在需要被调⽤的⽅法上加上@Async注解,则该⽅法会被异步调⽤2.@Async的使⽤
步骤⼀:在启动类上⾯加@EnableAsync注解
@EnableAsync
@SpringBootApplication
public class OperationApplication {
/**
* 启动类
*/
public static void main(String[] args){
SpringApplication.run(OperationApplication.class, args);
}
}
或者
创建⼀个配置类,在配置类上⾯加@EnableAsync注解
@Configuration
@EnableAsync
public class ThreadPoolConfig {
}
注意:@Async默认启动的线程池,属性
步骤⼆:在对应的⽅法上加@Async注解
@Async
public void method(){
log.info("执⾏该线程的名字为:"+ Thread.currentThread().getName());
}
3.@Async的使⽤原理
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public@interface Async {
/
**
* A qualifier value for the specified asynchronous operation(s).
* <p>May be ud to determine the target executor to be ud when executing
* the asynchronous operation(s), matching the qualifier value (or the bean
* name) of a specific {@link urrent.Executor Executor} or
* {@link ask.TaskExecutor TaskExecutor}
* bean definition.
* <p>When specified on a class-level {@code @Async} annotation, indicates that the  * given executor should be ud for all methods within the class. Method-level u  * of {@code Async#value} always overrides any value t at the class level.
* @since 3.1.2
*/
String value()default"";
}
剖析注释可以发现
@Async 注解中有⼀个 value 属性,看注释应该是可以指定是哪个线程池的写⼀个demo
相关的依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
启动类
@EnableAsync// 开启异步注解
@SpringBootApplication
public class ThreadDemoApplication {
public static void main(String[] args){
SpringApplication.run(ThreadDemoApplication.class, args);
}
}
调⽤的⽅法
@Slf4j
@Service
public class AsyncService {
@Async
public void method(){
log.info("执⾏该线程的名字为:"+ Thread.currentThread().getName());
}
}
写⼀个调⽤异步⽅法的接⼝
@Slf4j
@RestController
public class TestController {
@Resource
private AsyncService asyncService;
@GetMapping("/test")
public void test(){
log.info("执⾏test⽅法的线程的名字为:"+ Thread.currentThread().getName());
}
}
调⽤结果
INFO 22864---[        task-1]AsyncService      :执⾏该线程的名字为:task-1为了⼀探默认线程池的配置,就⾏⿊盒压测⼀下
@Slf4j
@RestController
public class TestController {
@Resource
private AsyncService asyncService;
@GetMapping("/test")
public void test(@RequestParam("num") Integer num){
log.info("执⾏test⽅法的线程的名字为:"+ Thread.currentThread().getName());
for(int i =0; i < num; i++){
}
}
}
不多废话,直接进⾏100000次异步调⽤
localhost:8080/test?num=100000
发现控制台并未报错,单堆内存⼏乎要爆炸,怀疑可能是⼀个⽆界队列,任务有可能都进队列⾥⾯排队了,导致内存飙升
默认的线程池有导致内存溢出的风险。
可以通过创建⾃定义线程池代替默认线程池
@Configuration
@EnableAsync
public class ThreadPoolConfig {
@Bean("taskExecutor")
public Executor taskExecutor(){
ThreadPoolTaskExecutor taskExecutor =new ThreadPoolTaskExecutor();
taskExecutor.tCorePoolSize(10);
taskExecutor.tMaxPoolSize(50);
taskExecutor.tQueueCapacity(200);
taskExecutor.tKeepAliveSeconds(60);
taskExecutor.tThreadNamePrefix("Thread-");
taskExecutor.tAwaitTerminationSeconds(60);
return taskExecutor;
}
}
控制台
2021-12-2418:18:38.014  INFO 10688---[      Thread-30]AsyncService      :执⾏该线程的名字为:Thread-30
2021-12-2418:18:38.014  INFO 10688---[      Thread-2]AsyncService      :执⾏该线程的名字为:Thread-2
2021-12-2418:18:38.014  INFO 10688---[      Thread-8]AsyncService      :执⾏该线程的名字为:Thr
ead-8
2021-12-2418:18:38.014  INFO 10688---[      Thread-15]AsyncService      :执⾏该线程的名字为:Thread-15
2021-12-2418:18:38.014  INFO 10688---[      Thread-25]AsyncService      :执⾏该线程的名字为:Thread-25
2021-12-2418:18:38.014  INFO 10688---[      Thread-5]AsyncService      :执⾏该线程的名字为:Thread-5
2021-12-2418:18:38.014  INFO 10688---[      Thread-31]AsyncService      :执⾏该线程的名字为:Thread-31
2021-12-2418:18:38.014  INFO 10688---[      Thread-24]AsyncService      :执⾏该线程的名字为:Thread-24
2021-12-2418:18:38.014  INFO 10688---[      Thread-22]AsyncService      :执⾏该线程的名字为:Thread-22
2021-12-2418:18:38.014  INFO 10688---[      Thread-9]AsyncService      :执⾏该线程的名字为:Thread-9
2021-12-2418:18:38.022 ERROR 10688---[nio-8080-exec-1]C.[.[.[/].[dispatcherServlet]: Servlet.rvice()for rvlet [dispatcherServlet] in conte
xt with[] threw exception [Request processing failed; nested exception is TaskRejectedException: Executor [ ThreadPoolExecutor@44a62e23[Running, pool size =50, active threads =50, queued tasks =91, completed tasks =1001]] did not accept task: AsyncExecutionInterceptor$$Lambda$580/2138858786@265a267e]with cau
RejectedExecutionException: Task FutureTask@293459fe rejected from ThreadPoolExecutor@ 44a62e23[Running, pool size =50, active threads =50, queued tasks =129, completed tasks =961]
at jectedExecution(ThreadPoolExecutor.java:2063)~[na:1.8.0_162]
ject(ThreadPoolExecutor.java:830)~[na:1.8.0_162]
ute(ThreadPoolExecutor.java:1379)~[na:1.8.0_162]
at AbstractExecutorService.submit(AbstractExecutorService.java:134)~[na:1.8.0_162]
说明 @Async使⽤了我们⾃定义的线程池,当超出最⼤线程数且队列满的时候,通过默认拒绝策略new
ThreadPoolExecutor.AbortPolicy()丢弃任务并抛出RejectedExecutionException异常
问题1:当不指定的时候,默认线程池是什么?具体配置是什么?看源码
value属性被使⽤的地⽅就⼀个,⾛

本文发布于:2023-05-05 19:14:41,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/82/534186.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:线程   默认   内存   名字   注解   导致   队列   指定
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图