SpringBoot框架@Async注解文章:SpringBoot異步調(diào)用@Async
SpringBoot線程池ThreadPoolTaskExecutor文章:SpringBoot線程池ThreadPoolTaskExecutor
ThreadPoolExecutor是JDK中的JUC中的線程池技術(shù)
SpringBoot線程池ThreadPoolTaskExecutor代碼實(shí)現(xiàn)
service層
- 創(chuàng)建一個service層的接口AsyncService,如下:
public interface AsyncService {
/**
* 執(zhí)行異步任務(wù)
* */
void executeAsync1() throws InterruptedException;
/**
* 執(zhí)行異步任務(wù)
* */
void executeAsync2() throws InterruptedException;
}
- 對應(yīng)的AsyncServiceImpl,實(shí)現(xiàn)如下:
/**
* 異步線程service
* @author jeffrey_hjf
*/
@Service
@Log
public class AsyncServiceImpl implements AsyncService {
@Override
@Async("asyncExecutor")
public void executeAsync1() throws InterruptedException {
System.out.println("MsgServer send A thread name->" + Thread.currentThread().getName());
Long startTime = System.currentTimeMillis();
TimeUnit.SECONDS.sleep(2);
Long endTime = System.currentTimeMillis();
System.out.println("MsgServer send A 耗時:" + (endTime - startTime));
}
@Override
@Async("asyncExecutor")
public void executeAsync2() throws InterruptedException {
System.out.println("MsgServer send B thread name->" + Thread.currentThread().getName());
Long startTime = System.currentTimeMillis();
TimeUnit.SECONDS.sleep(2);
Long endTime = System.currentTimeMillis();
System.out.println("MsgServer send B耗時:" + (endTime - startTime));
}
}
線程池配置
創(chuàng)建一個配置類ThreadPoolExecutorConfig拗盒,用來定義如何創(chuàng)建一個ThreadPoolExecutor,要使用@Configuration和@EnableAsync這兩個注解毙替,表示這是個配置類,并且是線程池的配置類践樱,如下所示:
/**
* @author jeffrey_hjf
*/
@Configuration
public class ThreadPoolExecutorConfig {
/**
* 獲得Java虛擬機(jī)可用的處理器個數(shù) + 1
*/
private static final int THREADS = Runtime.getRuntime().availableProcessors() + 1;
@Value("${async.executor.thread.core_pool_size}")
private int corePoolSize = THREADS;
@Value("${async.executor.thread.max_pool_size}")
private int maxPoolSize = 2 * THREADS;
@Value("${async.executor.thread.queue_capacity}")
private int queueCapacity = 1024;
@Value("${async.executor.thread.name.prefix}")
private String namePrefix = "async-service-";
final ThreadFactory threadFactory = new ThreadFactoryBuilder()
// -%d不要少
.setNameFormat(namePrefix + "%d")
.setDaemon(true)
.build();
/**
*
* @return
*/
@Bean("asyncExecutor")
public Executor asyncExecutor() {
return new ThreadPoolExecutor(corePoolSize, maxPoolSize,
5, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(queueCapacity),
threadFactory, (r, executor) -> {
//打印日志,添加監(jiān)控等
System.out.println("task is rejected!");
});
}
}
controller層
創(chuàng)建一個controller為Hello厂画,里面定義一個http接口,做的事情是調(diào)用Service層的服務(wù)拷邢,如下:
/**
* @ClassName UserController
* @Author jeffrey_hjf
* @Description User
**/
@RestController
@RequestMapping("/api")
@Log
public class UserController {
@Autowired
private AsyncService asyncService;
/**
* ThreadPoolExecutor線程池
* @return
*/
@GetMapping("/executeThreadPoolExecutor")
public String executeThreadPoolExecutor() throws Exception {
System.out.println("主線程 name -->" + Thread.currentThread().getName());
asyncService.executeAsync1();
asyncService.executeAsync2();
return "Hello World";
}
}
執(zhí)行效果
控制臺看見日志如下:
主線程 name -->http-nio-9090-exec-1
MsgServer send A thread name->async-service-0
MsgServer send B thread name->async-service-1
MsgServer send A 耗時:2000
MsgServer send B耗時:2000
如上日志所示袱院,我們可以看到controller的執(zhí)行線程是”nio-8080-exec-1”,這是tomcat的執(zhí)行線程解孙,而service層的日志顯示線程名為“async-service-0”坑填,顯然已經(jīng)在我們配置的線程池中執(zhí)行了,并且每次請求中弛姜,controller的起始和結(jié)束日志都是連續(xù)打印的脐瑰,表明每次請求都快速響應(yīng)了,而耗時的操作都留給線程池中的線程去異步執(zhí)行廷臼;
SpringBoot線程池擴(kuò)展ThreadPoolExecutor代碼實(shí)現(xiàn)
雖然我們已經(jīng)用上了線程池苍在,但是還不清楚線程池當(dāng)時的情況绝页,有多少線程在執(zhí)行,多少在隊列中等待呢寂恬?這里我創(chuàng)建了一個ThreadPoolTaskExecutor的子類续誉,改寫的方法:beforeExecute、afterExecute初肉、terminated酷鸦。這些方法可以添加日志、計時牙咏、監(jiān)控或統(tǒng)計信息收集等功能臼隔。
擴(kuò)展ThreadPoolExecutor類
public class ThreadPoolExecutorExtend extends ThreadPoolExecutor {
private final ThreadLocal startTime = new ThreadLocal();
private final AtomicLong numTasks = new AtomicLong();
private final AtomicLong totalTime = new AtomicLong();
public ThreadPoolExecutorExtend(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
public ThreadPoolExecutorExtend(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
}
public ThreadPoolExecutorExtend(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
}
public ThreadPoolExecutorExtend(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
try{
long endTime = System.currentTimeMillis();
long useTime = endTime - (long)startTime.get();
numTasks.incrementAndGet();
totalTime.addAndGet(useTime);
System.out.println("afterExecute " + r);
}finally{
super.afterExecute(r, t);
}
}
@Override
protected void beforeExecute(Thread t, Runnable r) {
super.beforeExecute(t, r);
System.out.println("beforeExecute " + r);
startTime.set(System.currentTimeMillis());
}
@Override
protected void terminated() {
try{
System.out.println("terminated avg time " + totalTime.get() + " " + numTasks.get());
}finally{
super.terminated();
}
}
}
修改ThreadPoolExecutorConfig配置類
修改ThreadPoolExecutorConfig.java的asyncExecutorExtend方法,將new ThreadPoolExecutor改為new ThreadPoolExecutorExtend妄壶,如下所示:
@Bean("asyncExecutorExtend")
public Executor asyncExecutorExtend() {
return new ThreadPoolExecutorExtend(corePoolSize, maxPoolSize,
5, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(queueCapacity),
threadFactory, (r, executor) -> {
//打印日志,添加監(jiān)控等
System.out.println("task is rejected!");
});
}
執(zhí)行效果
日志如下:
主線程 name -->http-nio-9090-exec-1
beforeExecute java.util.concurrent.FutureTask@372c5560
MsgServer send A thread name->async-service-0
MsgServer send A 耗時:2000
afterExecute java.util.concurrent.FutureTask@372c5560
SpringBoot框架@Async注解文章:SpringBoot異步調(diào)用@Async
SpringBoot線程池ThreadPoolTaskExecutor文章:SpringBoot線程池ThreadPoolTaskExecutor