异步线程的使用
- @Async需要在不同类使用才会产生异步效果,方法一定要从另一个类中调用,也就是从类的外部调用,类的内部调用是无效的
- 没有走Spring的代理类。因为@Transactional和@Async注解的实现都是基于Spring的AOP,而AOP的实现是基于动态代理模式实现的。那么注解失效的原因就很明显了,有可能因为调用方法的是对象本身而不是代理对象,因为没有经过Spring容器管理
- @SpringBootApplication启动类当中没有添加@EnableAsync注解
- 异步方法使用注解@Async的返回值只能为void或者Future
- 注解的方法必须是public方法。
- 如果需要从类的内部调用,需要先获取其代理类
AsyncConfig
package com.yymt.config;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 异步线程池的配置
*/
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
/**
* 一般情况下不会将队列大小设为:Integer.MAX_VALUE,也不会将核心线程数和最大线程数设为同样的大小,
* 这样的话最大线程数的设置都没什么意义了,你也无法确定当前 CPU 和内存利用率具体情况如何
*/
// 核心线程数,线程数定义了最小可以同时运行的线程数量
private static final int CORE_POOL_SIZE = 6;
// 当队列中存放的任务达到队列容量的时候,当前可以同时运行的线程数量变为最大线程数
private static final int MAX_POOL_SIZE = 10;
// 当新任务来的时候会先判断当前运行的线程数量是否达到核心线程数,如果达到的话,信任就会被存放在队列中
private static final int QUEUE_CAPACITY = 1000;
@Bean("myExecutor")
public Executor miaoshaTaskExecutor() {
// Spring 默认配置是核心线程数大小为1,最大线程容量大小不受限制,队列容量也不受限制。
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程数
executor.setCorePoolSize(CORE_POOL_SIZE);
// 最大线程数
executor.setMaxPoolSize(MAX_POOL_SIZE);
// 队列大小
executor.setQueueCapacity(QUEUE_CAPACITY);
// 当最大池已满时,此策略保证不会丢失任务请求,但是可能会影响应用程序整体性能。
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setThreadNamePrefix("sendWeb-ThreadPool-");
executor.initialize();
return executor;
}
@Override
public Executor getAsyncExecutor() {
return null;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return null;
}
/**
* ThreadPoolTaskExecutor 饱和策略定义:
* ThreadPoolExecutor.AbortPolicy:抛出 RejectedExecutionException来拒绝新任务的处理。
* ThreadPoolExecutor.CallerRunsPolicy:调用执行自己的线程运行任务。您不会任务请求。但是这种策略会降低对于新任务提交速度,
* 影响程序的整体性能。另外,这个策略喜欢增加队列容量。
* 如果您的应用程序可以承受此延迟并且你不能任务丢弃任何一个任务请求的话,你可以选择这个策略。
* ThreadPoolExecutor.DiscardPolicy: 不处理新任务,直接丢弃掉。
* ThreadPoolExecutor.DiscardOldestPolicy: 此策略将丢弃最早的未处理的任务请求。
*/
}
AsyncHandler
@Component
public class AsyncHandler {
@Autowired
private WebSocketServer webSocketServer;
@Async("myExecutor")
public void sendWeb(Map<String, Object> map) {
System.out.println("async start");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("async end");
webSocketServer.sendAll(map);
}
}
测试
@GetMapping("/test/{communityId}")
@ApiOperation(value = "test")
public R test(@PathVariable Long communityId) {
Map<String, Object> map = new HashMap<>();
map.put("communityId", communityId);
asyncHandler.sendWeb(map);
return R.ok();
}
如果需要从类的内部调用,需要先获取其代理类
// 使用hutool工 @Import(cn.hutool.extra.spring.SpringUtil.class)
AsyncHandler asyncHandler = SpringUtil.getBean("asyncHandler",AsyncHandler.class);
asyncHandler.sendWeb(map);