含义:
1,在方法上使用该@Async注解,申明该方法是一个异步任务;
2,在类上面使用该@Async注解,申明该类中的所有方法都是异步任务;
3,使用此注解的方法的类对象,必须是spring管理下的bean对象;
1.要想使用异步任务,需要在主类上开启异步配置,即,配置上@EnableAsync注解;spring中启用@Async。
// 基于Java配置的启用方式:
// 基于Java配置的启用方式:
@Configuration
@EnableAsync //开启多线程
public class ThreadPoolConfig {
@Bean("taskExecutor")
public Executor asyncServiceExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 设置核心线程数
executor.setCorePoolSize(5);
// 设置最大线程数
executor.setMaxPoolSize(20);
//配置队列大小
executor.setQueueCapacity(Integer.MAX_VALUE);
// 设置线程活跃时间(秒)
executor.setKeepAliveSeconds(60);
// 设置默认线程名称
executor.setThreadNamePrefix("水草博客项目");
// 等待所有任务结束后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
//执行初始化
executor.initialize();
return executor;
}
}
// Spring boot启用:
// Spring boot启用:
@EnableAsync
@EnableTransactionManagement
public class BlogApp {
public static void main(String[] args){
SpringApplication.run(BlogApp.class,args);
}
}
@Async应用默认线程池
方法上一旦标记了这个@Async注解,当其它线程调用这个方法时,就会开启一个新的子线程去异步处理该业务逻辑。
@Async注解在使用时,如果不指定线程池的名称,则使用Spring默认的线程池,Spring默认的线程池为SimpleAsyncTaskExecutor。
// 期望此操作在线程池 执行 不会影响原有的主线程
@Async("taskExecutor")
// taskExecutor ---------指定的线程池
public void updateViewCount(ArticleMapper articleMapper,Article article){
System.out.println(Thread.currentThread().getName() + " Start. Time = " + new Date());
updateViewCountDetil(articleMapper,article);
System.out.println(Thread.currentThread().getName() + " End. Time = " + new Date());
}
private void updateViewCountDetil(ArticleMapper articleMapper,Article article){
int viewCounts=article.getViewCounts();
Article articleUpdate = new Article();
articleUpdate.setViewCounts(viewCounts + 1);
LambdaUpdateWrapper<Article> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(Article::getId,article.getId());
updateWrapper.eq(Article::getViewCounts,viewCounts);
articleMapper.update(articleUpdate,updateWrapper);
try {
//睡眠5秒 证明不会影响主线程的使用
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
无返回值调用
基于@Async无返回值调用,直接在使用类,使用方法(建议在使用方法)上,加上注解。若需要抛出异常,需手动new一个异常抛出。
/**
* 带参数的异步调用 异步方法可以传入参数
* 对于返回值是void,异常会被AsyncUncaughtExceptionHandler处理掉
* @param s
*/
@Async
public void asyncInvokeWithException(String s) {
log.info("asyncInvokeWithParameter, parementer={}", s);
throw new IllegalArgumentException(s);
}
有返回值Future调用
/**
* 异常调用返回Future
* 对于返回值是Future,不会被AsyncUncaughtExceptionHandler处理,需要我们在方法中捕获异常并处理
* 或者在调用方在调用Futrue.get时捕获异常进行处理
*
* @param i
* @return
*/
@Async
public Future<String> asyncInvokeReturnFuture(int i) {
log.info("asyncInvokeReturnFuture, parementer={}", i);
Future<String> future;
try {
Thread.sleep(1000 * 1);
future = new AsyncResult<String>("success:" + i);
throw new IllegalArgumentException("a");
} catch (InterruptedException e) {
future = new AsyncResult<String>("error");
} catch(IllegalArgumentException e){
future = new AsyncResult<String>("error-IllegalArgumentException");
}
return future;
}