利用springboot提供的线程池,实现参数可配置的线程池。
#线程池参数按需设置,不设置的时候给默认值
threadpool:
#核心线程数(默认10)
core_pool_size: 10
#最大线程数(默认200)
max_pool_size: 200
#队列大小(默认1024)
queue_capacity: 1024
#空闲线程活跃时间(秒)(默认60)
keep_alive_seconds: 60
#默认线程名称(area-pool-)
prefix_name: area-pool-
如果想使用@Async注解来完成异步任务的话,需要在配置类上添加注解@EnableAsync,如果不使用注解完成异步的话,此注解可以省略。直接上代码吧:
package com.diwork.intelliv.workbench.analysis.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
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 java.util.concurrent.ThreadPoolExecutor;
@Configuration
@EnableAsync
public class ThreadPoolAsyncConfig {
private final static Logger logger = LoggerFactory.getLogger(ThreadPoolAsyncConfig.class);
/**
* 核心线程数
*/
@Value("${threadpool.core_pool_size:10}")
private int corePoolSize;
/**
* 最大线程数
*/
@Value("${threadpool.max_pool_size:200}")
private int maxPoolSize;
/**
* 队列大小
*/
@Value("${threadpool.queue_capacity:1024}")
private int queueCapacity;
/**
* 空闲线程活跃时间(秒)
*/
@Value("${threadpool.keep_alive_seconds:60}")
private int keepAliveSeconds;
/**
* 默认线程名称
*/
@Value("${threadpool.prefix_name:area-pool-test}")
private String threadNamePrefix;
@Bean("threadPoolTaskExecutor")
public ThreadPoolTaskExecutor asyncServiceExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
logger.info("---------- 线程池开始加载 ----------");
// 设置核心线程数
threadPoolTaskExecutor.setCorePoolSize(corePoolSize);
// 设置最大线程数
threadPoolTaskExecutor.setMaxPoolSize(maxPoolSize);
// 配置队列大小
threadPoolTaskExecutor.setQueueCapacity(queueCapacity);
// 设置线程活跃时间(秒)
threadPoolTaskExecutor.setKeepAliveSeconds(keepAliveSeconds);
// 设置默认线程名称
threadPoolTaskExecutor.setThreadNamePrefix(threadNamePrefix);
// 设置拒绝策略
// CallerRunsPolicy:不在新线程中执行任务,而是由调用者所在的线程来执行
threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 执行初始化
threadPoolTaskExecutor.initialize();
logger.info("corePoolSize [{}], maxPoolSize [{}],queueCapacity [{}], keepAliveSeconds [{}], threadNamePrefix [{}]",
corePoolSize,
maxPoolSize,
queueCapacity,
keepAliveSeconds,
threadNamePrefix);
logger.info("---------- 线程池加载完成 ----------");
return threadPoolTaskExecutor;
}
}
service类,注意注解的添加,这里需要注意的一点就是添加@Async想要实现异步的效果的话,必须保证调用者和异步方法不在同一个类中,否则,异步不生效。这一点很关键。
异步接口类AsyncService
package com.example.springboottest1.service;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Service
public interface AsyncService {
/**
* 执行异步任务,注意这里的threadPoolTaskExecutor要跟配置类中的一致
*/
@Async("threadPoolTaskExecutor")
void executeAsync();
}
异步实现类AsyncServiceImpl
package com.example.springboottest1.serviceimp;
import com.example.springboottest1.service.AsyncService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
@Service
public class AsyncServiceImpl implements AsyncService {
private static final Logger logger = LoggerFactory.getLogger(AsyncServiceImpl.class);
@Override
public void executeAsync() {
try {
logger.info("============================="+Thread.currentThread().getName());
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@Resource(name = "threadPoolTaskExecutor")
private ThreadPoolTaskExecutor threadPool;
Future task = threadPool.submit(queryThread);
package com.example.springboottest1.controller;
import com.example.springboottest1.service.AsyncService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ThreadController {
@Autowired
private AsyncService asyncService;
@GetMapping("/sss")
public String sss(){
for (int i = 1; i <= 100; i++) {
asyncService.executeAsync();
}
return "OK";
}
}
第五,如果想要统计线程的使用情况,可以自定义一个类,并继承springboot提供的线程池类即可。只要把配置类中的
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
改为
ThreadPoolTaskExecutor threadPoolTaskExecutor = new VisiableThreadPoolTaskExecutor();
package com.diwork.intelliv.workbench.analysis.exe.block;
/**
*
*/
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.concurrent.ListenableFuture;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
/**
* @className VisiableThreadPoolTaskExecutor
* @description: TODO
* @author Lancy
* @date 2021/6/25 9:52
* @version 1.0
*/
public class VisiableThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {
private static final Logger logger = LoggerFactory.getLogger(VisiableThreadPoolTaskExecutor.class);
private void showThreadPoolInfo(String prefix) {
ThreadPoolExecutor threadPoolExecutor = getThreadPoolExecutor();
if (null == threadPoolExecutor) {
return;
}
logger.info("{}, {},taskCount [{}], completedTaskCount [{}], activeCount [{}], queueSize [{}]",
this.getThreadNamePrefix(),
prefix,
threadPoolExecutor.getTaskCount(),
threadPoolExecutor.getCompletedTaskCount(),
threadPoolExecutor.getActiveCount(),
threadPoolExecutor.getQueue().size());
}
@Override
public void execute(Runnable task) {
showThreadPoolInfo("1. do execute");
super.execute(task);
}
@Override
public void execute(Runnable task, long startTimeout) {
showThreadPoolInfo("2. do execute");
super.execute(task, startTimeout);
}
@Override
public Future> submit(Runnable task) {
showThreadPoolInfo("1. do submit");
return super.submit(task);
}
@Override
public Future submit(Callable task) {
showThreadPoolInfo("2. do submit");
return super.submit(task);
}
@Override
public ListenableFuture> submitListenable(Runnable task) {
showThreadPoolInfo("1. do submitListenable");
return super.submitListenable(task);
}
@Override
public ListenableFuture submitListenable(Callable task) {
showThreadPoolInfo("2. do submitListenable");
return super.submitListenable(task);
}
}
至此完成线程的工作,可以去使用了!