- 首先我们需要在调用异步方法的类型添加如下注解
@Configuration
@EnableAsync
- 然后再异步的方法上添加如下注解
@Async
这样就可以使用了
实例如下:
/**
* 调到异步方法类
*/
@Configuration
@EnableAsync
public class PmZdfa extends Node{
@Autowired
private AsySendMsg asySendMsg;
@Override
public EnginResponse excute(EnginRequest enginRequest) {
Thread thread = Thread.currentThread();
System.out.println("================Thread: " + thread);
System.out.println("================Thread Id: " + thread.getId());
System.out.println("================Thread Name: " + thread.getName());
System.out.println("================Thread Group: " + thread.getThreadGroup());
System.out.println("================Thread Priority: " + thread.getPriority());
asySendMsg.sendMsg();
}
/**
* 异步方法具体实现
*/
@Component("asySendMsg")
public class AsySendMsg {
@Autowired
private ISysMsgInterface iSysMsgInterface;
@Async
public void sendMsg(){
Thread thread = Thread.currentThread();
System.out.println("================Thread: " + thread);
System.out.println("================Thread Id: " + thread.getId());
System.out.println("================Thread Name: " + thread.getName());
System.out.println("================Thread Group: " + thread.getThreadGroup());
System.out.println("================Thread Priority: " + thread.getPriority());
}
}
//控制台输出:
================Thread: Thread[DubboServerHandler-10.40.231.184:20985-thread-19,5,main]
================Thread Id: 59
================Thread Name: DubboServerHandler-10.40.231.184:20985-thread-19
================Thread Group: java.lang.ThreadGroup[name=main,maxpri=10]
================Thread Priority: 5
================Thread: Thread[SimpleAsyncTaskExecutor-1,5,main]
================Thread Id: 60
================Thread Name: SimpleAsyncTaskExecutor-1
================Thread Group: java.lang.ThreadGroup[name=main,maxpri=10]
================Thread Priority: 5
@Async默认异步配置使用的是SimpleAsyncTaskExecutor,该线程池默认来一个任务创建一个线程,若系统中不断的创建线程,最终会导致系统占用内存过高,引发OutOfMemoryError错误。针对线程创建问题,SimpleAsyncTaskExecutor提供了限流机制,通过concurrencyLimit属性来控制开关,当concurrencyLimit>=0时开启限流机制,默认关闭限流机制即concurrencyLimit=-1,当关闭情况下,会不断创建新的线程来处理任务。基于默认配置,SimpleAsyncTaskExecutor并不是严格意义的线程池,达不到线程复用的功能。
@Async应用自定义线程池
自定义线程池,可对系统中线程池更加细粒度的控制,方便调整线程池大小配置,线程执行异常控制和处理。在设置系统自定义线程池代替默认线程池时,虽可通过多种模式设置,但替换默认线程池最终产生的线程池有且只能设置一个(不能设置多个类继承AsyncConfigurer)自定义线程池有如下模式:
- 重新实现接口AsyncConfigurer
- 继承AsyncConfigurerSupport
- 配置由自定义的TaskExecutor替代内置的任务执行器
通过查看Spring源码关于@Async的默认调用规则,会优先查询源码中实现AsyncConfigurer这个接口的类,实现这个接口的类为AsyncConfigurerSupport。但默认配置的线程池和异步处理方法均为空,所以,无论是继承或者重新实现接口,都需指定一个线程池。且重新实现 public Executor getAsyncExecutor()方法。
1.实现接口AsyncConfigurer
2.继承AsyncConfigurerSupport
3.配置自定义的TaskExecutor
由于AsyncConfigurer的默认线程池在源码中为空,Spring通过beanFactory.getBean(TaskExecutor.class)先查看是否有线程池,未配置时,通过beanFactory.getBean(DEFAULT_TASK_EXECUTOR_BEAN_NAME, Executor.class),又查询是否存在默认名称为TaskExecutor的线程池。
所以可在项目中,定义名称为TaskExecutor的bean生成一个默认线程池。也可不指定线程池的名称,申明一个线程池,本身底层是基于TaskExecutor.class便可。
比如:
Executor.class:ThreadPoolExecutorAdapter->ThreadPoolExecutor->AbstractExecutorService->ExecutorService->Executor
这样的模式,最终底层为Executor.class,在替换默认的线程池时,需设置默认的线程池名称为TaskExecutor
TaskExecutor.class:ThreadPoolTaskExecutor->SchedulingTaskExecutor->AsyncTaskExecutor->TaskExecutor
这样的模式,最终底层为TaskExecutor.class,在替换默认的线程池时,可不指定线程池名称。