线程池的优势
总体来说,线程池有如下的优势:
(1)降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
(2)提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
(3)提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。
4个参数的设计:
corePoolSize(必需):核心线程数。默认情况下,核心线程会一直存活,但是当将 allowCoreThreadTimeout 设置为 true 时,核心线程也会超时回收。
maximumPoolSize(必需):线程池所能容纳的最大线程数。当活跃线程数达到该数值后,后续的新任务将会阻塞。
keepAliveTime(必需):线程闲置超时时长。如果超过该时长,非核心线程就会被回收。如果将 allowCoreThreadTimeout 设置为 true 时,核心线程也会超时回收。
unit(必需):指定 keepAliveTime 参数的时间单位。常用的有:TimeUnit.MILLISECONDS(毫秒)、TimeUnit.SECONDS(秒)、TimeUnit.MINUTES(分)。
workQueue(必需):任务队列。通过线程池的 execute() 方法提交的 Runnable 对象将存储在该参数中。其采用阻塞队列实现。
threadFactory(可选):线程工厂。用于指定为线程池创建新线程的方式。
handler(可选):拒绝策略。当达到最大线程数时需要执行的饱和策略。
线程池创建的四种方式:
newCachedThreadPool
创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程
newFixedThreadPool
创建一个指定工作线程数量的线程池。每当提交一个任务就创建一个工作线程,如果工作线程数量达到线程池初始的最大数,则将提交的任务存入到池队列中。
newSingleThreadExecutor
创建一个单线程化的Executor,即只创建唯一的工作者线程来执行任务,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO,优先级)执行。如果这个线程异常结束,会有另一个取代它,保证顺序执行。
newScheduledThreadPool
创建一个定长的线程池,而且支持定时的以及周期性的任务执行,支持定时及周期性任务执行。
拒绝策略(handler)
线程池拒绝策略是指在线程池中所有线程都被占用的情况下,如何处理新的任务请求。常见的线程池拒绝策略有以下四种:
- AbortPolicy(默认策略):直接抛出RejectedExecutionException异常,阻止系统正常运行。
- CallerRunsPolicy:直接在主线程中运行被拒绝的任务,如果提交任务的速度过快,可能会导致主线程负载过大而影响系统正常运行。
- DiscardPolicy:直接丢弃被拒绝的任务,不予任何处理。
- DiscardOldestPolicy:丢弃任务队列中最老的任务,然后重新尝试执行任务提交操作。如果线程池的容量已经达到最大值,那么这些被丢弃的任务将不会被执行。
最佳解决方案取决于应用程序的要求和场景。一般而言,建议使用自定义的拒绝策略以满足特定的需求。
以下是一些可能的自定义拒绝策略:
- 队列容量有限制,当队列已满时,将任务直接执行,而不是放入队列。这种策略可以确保任务不会被丢弃,但可能会导致主线程负载过大。
- 实现一个自适应的拒绝策略,如果线程池中的线程数已经达到最大值,那么就逐渐增加线程池的最大容量,并减少拒绝策略的频率,以便更好地处理任务请求。
- 将任务放入一个分布式的任务队列中,这样可以将任务分发到多个节点上执行,从而提高整体的吞吐量。
最终的最佳解决方案应该是根据具体的业务需求和场景来选择合适的拒绝策略,并进行适当的调整和优化。
执行流程
示例代码:
thread:
# 核心线程池数
corePoolSize:
# 最大线程池数
maxPoolSize:
# 任务队列的容量
queueCapacity:
# 非核心线程的存活时间
keepAlive:
# 创建线程的等待时间
awaitTerminationSeconds:
package com.demo.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.Optional;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 线程池
*/
@Configuration
public class ThreadPoolTaskExecutorConfig implements AsyncConfigurer {
// 当前机器核数
public static final int cpuNum = Runtime.getRuntime().availableProcessors();
@Value("${thread.corePoolSize}")
private Integer corePoolSize;
@Value("${thread.maxPoolSize}")
private Integer maxPoolSize;
@Value("${thread.queueCapacity}")
private Integer queueCapacity;
@Value("${thread.keepAlive}")
private Integer keepAlive;
@Value("${thread.awaitTerminationSeconds}")
private Integer awaitTerminationSeconds;
@Override
@Bean
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
// 核心线程池数
threadPoolTaskExecutor.setCorePoolSize(optionl(corePoolSize, cpuNum));
//最大线程池数
threadPoolTaskExecutor.setMaxPoolSize(optionl(maxPoolSize, cpuNum * 2));
//任务队列的容量
threadPoolTaskExecutor.setQueueCapacity(optionl(queueCapacity, 3));
//非核心线程的存活时间-最大空闲时间
threadPoolTaskExecutor.setKeepAliveSeconds(optionl(keepAlive, 10));
threadPoolTaskExecutor.setThreadNamePrefix("test-thread-");
// 抛异常规则
threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
threadPoolTaskExecutor.initialize();
// 创建线程的等待时间
threadPoolTaskExecutor.setAwaitTerminationSeconds(optionl(awaitTerminationSeconds, 10));
return threadPoolTaskExecutor;
}
/**
* 判空-替换
*
* @param key 原值
* @param key2 替换值
* @return 结果
*/
public Integer optionl(Integer key, Integer key2) {
// 如果key为空则赋值为key2
return Optional.ofNullable(key).orElse(key2);
}
}
public static void main(String[] args) {
ThreadPoolTaskExecutorConfig threadPoolTaskExecutorConfig = new ThreadPoolTaskExecutorConfig();
// 创建线程池
Executor executor = threadPoolTaskExecutorConfig.getAsyncExecutor();
executor.execute(()->{
System.out.println("内容");
});
}