- 俗话说
双拳难敌4手,人多好办事
;单一个人干活比较吃力的时候,这时我们就需要摇人儿了。- 当单线程执行任务效率较低时,我们就考虑使用多线程解决问题,同时注意数据同步问题。
线程池参数:
corePoolSize
线程池基本线程数量,打底数量,不会被回收,长期维护的线程maximumPoolSize
最大线程数量,当前 核心线程、等待队列都满时,线程池会创建线程运行直到达到最大线程池数keepAliveTime
非核心线程的空闲线程的存活时长TimeUnit
存活时长单位,如TimeUnit.MILLISECONDS
BlockingQueue<>
等待队列,核心线程数满时,后提交到线程池的线程加入队列排队等待RejectedExecutionHandler
当线程数量超过,最大线程数+队列数时,再次进入线程池的线程会触发拒绝策略手动创建线程池:
- 一般建议不丢弃任务,丢弃可能少数据,采用策略 CallerRunsPolicy();返回发起线程继续执行,一般是main 线程
- 线程池的核心线程数,一般根据CPU 数,以及 阻塞系数确定,0~1,系数越高,执行任务时间越长
- 分为 IO型、CPU型,根据情况具体配置
private static final int core= Runtime.getRuntime().availableProcessors();
private static final int waitCount = 20;
private static final ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor
(core,
core + waitCount,
60*10, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(waitCount),
new CustomizableThreadFactory("线程池-"),
new ThreadPoolExecutor.CallerRunsPolicy());
jdk创建,场景一 :
- 执行较多耗时任务,不需要实时刷新状态,任务完成修改数据状态,前端查询更新
- 这里都是,比如接口调用一次,执行到多线程调用,就会往线程池添加一个执行任务线程,或者由空闲线程接手
//不需要返回值异步执行时
pool.execute(() -> {
materialService.toConvertForAdd(trainInformation);
esHandle(trainInformation);
});
//需要返回值时
Callable<Boolean> c1 = ()-> exampleServcie.cleanHouse(1);
Callable<Boolean> c2 = ()-> exampleServcie.cleanHouse(2);
Callable<Boolean> c3 = ()-> exampleServcie.cleanHouse(3);
Callable<Boolean> c4 = ()-> exampleServcie.cleanHouse(4);
List<Future<Boolean>> futures = poolExecutor.invokeAll(Arrays.asList(c1, c2, c3, c4));
futures.forEach(e->{
try {
System.out.println(e.get());
} catch (InterruptedException | ExecutionException ex) {
ex.printStackTrace();
}
});
Spring boot 工具类运用
ThreadPoolTaskExecutor
@EnableAsync
@Configuration
public class PoolConfig {
/**
* 服务核数
*/
private static final int CORE = Runtime.getRuntime().availableProcessors();
/**
* - CPU密集型,eg: 加密、解密、压缩、计算
* - 高并发、任务执行时间短业务,线程数可以设置为CPU核数+1,减少线程上下文切换
* - 默认设置策略 CallerRunsPolicy(),让发出线程继续执行任务,不考虑任务顺序,主数据不丢失
* @return Executor
*/
@Bean("cpuDefaultThreadPool")
public Executor cpuDefaultThreadPool(){
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(CORE+1);
taskExecutor.setQueueCapacity(20);
taskExecutor.setMaxPoolSize(CORE+21);
taskExecutor.setKeepAliveSeconds(60*10);
taskExecutor.setThreadNamePrefix("cpuPool-");
taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
taskExecutor.initialize();
return taskExecutor;
}
/**
* - 耗时型,eg : 数据库、文件读写,网络通信等任务 -> 不会特别消耗 CPU资源,但是IO 操作很耗时间
* - 默认设置策略 CallerRunsPolicy(),让发出线程继续执行任务,不考虑任务顺序,主数据不丢失
* - blockingCoefficient 阻塞系数
* @return Executor
*/
@Bean("ioDefaultThreadPool")
public Executor ioDefaultThreadPool(){
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
//每个任务80%的时间处于阻塞状态而只有10%的时间在干活
//保守值cpu数量的2倍
double blockingCoefficient =0.8;
int poolSize = (int) (CORE / (1- blockingCoefficient));
taskExecutor.setCorePoolSize(poolSize);
taskExecutor.setQueueCapacity(20);
taskExecutor.setMaxPoolSize(poolSize+20);
taskExecutor.setKeepAliveSeconds(60*30);
taskExecutor.setThreadNamePrefix("ioPool-");
taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
taskExecutor.initialize();
return taskExecutor;
}
}
普通运用
@Autowired
ThreadConfig threadConfig;
threadConfig.cpuDefaultThreadPool();
@Autowired
private ThreadConfig threadConfig;
@GetMapping("/test")
public void test(){
List<Integer> test = getBatchListTest();
List<List<Integer>> lists = Lists.partition(test, 100);
Executor executor = threadConfig.getExecutor();
List<CompletableFuture> results = new ArrayList<>();
for (List<Integer> list : lists) {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
toDo(list);
return "";
}, executor);
results.add(future);
}
CompletableFuture.allOf(results.toArray(new CompletableFuture[]{})).join();
}
List<Integer> getBatchListTest(){
List<Integer> res = new LinkedList<>();
for (int i = 0; i < 1000; i++) {
res.add(i);
}
return res;
}
void toDo(List<Integer> list){
System.out.println("线程:"+Thread.currentThread().getId()+"集合:"+list.size());
}
@Async("cpuDefaultThreadPool")
CompletableFuture<Boolean> cleanHouseAsync(Integer range);
@Override
public CompletableFuture<Boolean> cleanHouseAsync(Integer range) {
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("Async: 打扫完了"+range+"号房间");
return CompletableFuture.completedFuture(true);
}