Spring的@Async异步编程
使用@Async注解时,推荐使用自定义线程池的模式;查看源码,@Async的默认线程池为SimpleAsyncTaskExecutor,默认线程池有如下弊端:
在线程池应用中,参考阿里巴巴java开发规范:线程池不允许使用Executors去创建,不允许使用系统默认的线程池,推荐通过ThreadPoolExecutor的方式,这样的处理方式让开发的工程师更加明确线程池的运行规则,规避资源耗尽的风险。
一、自定义异步线程池
package cn.itcast.user.config;
import java.util.concurrent.Executor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import lombok.extern.slf4j.Slf4j;
/**
* 自定义线程池<br/><br/>
*
* 使用@Async注解时,推荐使用自定义线程池的模式
* @author Lynch
*
*/
@EnableAsync
@Configuration
@Slf4j
public class TaskPoolConfig {
@Bean("taskExecutor")
public Executor taskExecutor() {
//参数初始化
//private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
//核心线程数量大小
//private static final int corePoolSize = Math.max(2, Math.min(CPU_COUNT - 1, 4));
//线程池最大容纳线程数
//private static final int maximumPoolSize = CPU_COUNT * 2 + 1;
//返回可用处理器的Java虚拟机的数量 16
int i = Runtime.getRuntime().availableProcessors();
log.info("系统最大线程数 : " + i);
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//核心线程池大小
executor.setCorePoolSize(12);
//最大线程数
executor.setMaxPoolSize(20);
//配置队列容量,默认值为Integer.MAX_VALUE
executor.setQueueCapacity(99999);
//活跃时间
executor.setKeepAliveSeconds(60);
//线程名字前缀
executor.setThreadNamePrefix("asyncServiceExecutor -");
//设置此执行程序应该在关闭时阻止的最大秒数,以便在容器的其余部分继续关闭之前等待剩余的任务完成他们的执行
executor.setAwaitTerminationSeconds(60);
//等待所有的任务结束后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
return executor;
}
}
二、AsyncService
package cn.itcast.user.service;
/**
* 异步发送短信/邮件
*
* @author Lynch
*/
public interface AsyncService {
/**
* 发送短信
*
* @author Lynch
*/
void sendSms();
/**
* 发送邮件
*
* @author Lynch
*/
void sendEmail();
}
三、使用@Async注解异步执行——AsyncServiceImpl
package cn.itcast.user.service.impl;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import cn.itcast.user.service.AsyncService;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class AsyncServiceImpl implements AsyncService {
@Override
@Async("taskExecutor")
public void sendSms() {
try {
Thread.sleep(3000);
log.info("发送短信成功");
} catch (Exception e) {
log.error("发送短信异常 -> ", e);
}
}
@Override
@Async("taskExecutor")
public void sendEmail() {
try {
Thread.sleep(2000);
log.info("发送email成功");
} catch (Exception e) {
log.error("发送email异常 -> ", e);
}
}
}
四、单元测试——AsyncServiceTest
package cn.itcast.user.service;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import cn.itcast.user.BaseTest;
public class AsyncServiceTest extends BaseTest {
@Autowired
private AsyncService asyncService;
@Test
public void send() {
long begin = System.currentTimeMillis();
asyncService.sendSms();
asyncService.sendEmail();
System.out.println("执行耗时:" + (System.currentTimeMillis() - begin) + "毫秒");
}
}