异步任务@Async使⽤和失效原因
因业务需要,经常会遇到主线程中包含其他关联业务,然关联业务的执⾏结果对主线程的返回结果没有直接影响或⽆影响。此时,能让主线程更顺畅的执⾏,并给客户带来好的客户体验,我们⼀般会将该关联业务做异步处理或类似的处理(如:消息队列)。然后Spring为我们提供了开启异步任务的⽅法。
⼀、Springboot 使⽤异步任务
1、SpringBootApplication启动类添加@EnableAsync注解;
2、@Async使⽤
(1)类或者⽅法中使⽤@Async注解,类上标有该注解表⽰类中⽅法都是异步⽅法,⽅法上标有该注解表⽰⽅法是异步⽅法;
(2)@Async(“threadPool”),threadPool为⾃定义线程池,这样可以保证主线程中调⽤多个异步任务时能更⾼效的执⾏。
3、实例、分析
开启异步服务
package;
import SpringApplication;
import SpringBootApplication;
import EnableAsync;
@SpringBootApplication
@EnableAsync
public class RedisApplication {
public static void main(String[] args){
SpringApplication.run(RedisApplication.class,args);
}
}
创建线程池
import Configuration;
import ThreadPoolTaskExecutor;
import Executor;
@Configuration
public class AsyncService {
private static final int core =10;//核⼼线程数
private static final int queueNum =10;//队列容量
private static final int max =50;//最⼤线程数
@Bean(name ="executeThread")
public Executor executeThread(){
ThreadPoolTaskExecutor taskExecutor =new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(core);
taskExecutor.setMaxPoolSize(max);
taskExecutor.setQueueCapacity(queueNum);
taskExecutor.setRejectedExecutionHandler(new MyThreadRejectedHandler());//线程池拒绝策略        taskExecutor.initialize();
return taskExecutor;
}
}
⾃定义拒绝策略
package;
import RejectedExecutionHandler;
import ThreadPoolExecutor;
public class MyThreadRejectedHandler implements RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor){
}
}
执⾏异步调⽤
import Component;
import ExecutionException;
import Future;
import TimeUnit;
import TimeoutException;
@Component
public class ExecuteAsyncMethod {
private int num =10000;
@Async(value ="executeThread")
public Future<String>execute(){
for(int i =0; i <100; i++){
num--;
}
return new Future<String>(){
@Override
public boolean cancel(boolean mayInterruptIfRunning){
return false;
}
@Override
public boolean isCancelled(){
return false;
}
@Override
public boolean isDone(){
return false;
}
@Override
public String get()throws InterruptedException, ExecutionException {
return""+num;
}
@Override
public String get(long timeout, TimeUnit unit)throws InterruptedException, ExecutionException, TimeoutException { return null;
}
};
}
@Async(value ="executeThread")
public String execute2(){
for(int i =0; i <100; i++){
num--;
}
return""+num;
}
springboot aop}
注意: 如果想要在异步调⽤⽅法后有返回值,那么需要使⽤Future做返回值,否则调⽤⽅返回数据为null
如上execute和execute2⽅法。
import Autowired;
import RequestMapping;
import RestController;
import ExecutionException;
import Future;
@RestController
public class MyController {
@Autowired
private ExecuteAsyncMethod executeAsyncMethod;
@RequestMapping("/test")
public String execute()throws ExecutionException, InterruptedException {
Future<String> execute = ute();
System.out.());
String s1 = ute2();
System.out.println(s1);
return" --- "+ s1;
}
}
⾄此,Springboot 调⽤多个异步任务使⽤实例完成。
@Async注解 分析
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public@interface Async {
String value()default"";
}
通过查看@Async源码可以看出来,@Target 的值是类和⽅法,所有异步注解可以作⽤在⽅法体上⾯,也可以作⽤在类上⾯。
以上是项⽬使⽤,可正常使⽤,因此验证忽略!
⼆、Spring boot异步任务@Async失效问题
总结:
1、启动类是否开启异步服务;
2、在定义异步⽅法的同⼀个类中,调⽤带有@Async注解⽅法,该⽅法则⽆法异步执⾏;
3、注解的⽅法必须是public⽅法,不能是static;
4、没有⾛Spring的代理类。因为@Transactional和@Async注解的实现都是基于Spring的AOP,⽽AOP的实现是基于动态代理模式实现的。那么注解失效的原因就很明显了,有可能因为调⽤⽅法的是对象本⾝⽽不是代理对象,因为没有经过Spring容器管理。

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