动态线程池技术的应用
提出问题:
1、为何要使用动态线程池?
2、使用动态线程池有何优点?
3、解决了哪些问题?
问题的发现:
1、为何要使用动态线程池?
我们可能很多时候都会使用池化技术,例如数据库的连接池(druid),JDK线程池,JVM的对象池等等,它们的目的建时为了减少资源创建的花销,在并发量较大的时候,系统无法准确预估要创建多少线程,假如有的请求可以申请非常多的系统资源,如果不加以限制的话,系统稳定性将大大降低。池化技术,解决了资源分配问题的疼点,使得资源利用率大大提高。
不过,Jdk自带的线程池,并不是那么的完美,我们很难一开始就预估好线程池的参数,所以我希望可以设计一个可以动态调整参数的线程池去适应并发量的突发性,以及提高系统的可伸缩性。
2、使用动态线程池有何优点?
很显然,假如我们现在的业务是希望系统在预警的时候可以给监控人员发送消息,监控人员可以在后天管理系统当中,调整线程池的参数(调参boy😊),使得系统可以承受住更大的并发量,高峰期过了以后,我们希望系统的资源可以回收给其他地方利用,那么同样需要监控人员再次调整线程池的参数。通过这样的操作,即便我们不知道怎么设置线程池参数才合适,也可以在高峰预警的时候,紧急调整线程池的参数,从而达到系统免维护升级。
3、解决了哪些问题?
很显然,资源利用率提高了,本身就是池化技术,就集成了池化技术的传统优点,然而,更重要的是它设计成可以动态调整阻塞队列大小,核心线程数大小,最大线程数大小,以及回绝的策略,所以可以不用重启系统也可以做到修改线程池参数,从而达到动态调整系统性能的一种方式,增加了系统的可伸缩性。
具体实现:
- 首先我们使用的核心是使用JDK自带的 ThreadPoolExecutor 类,它提供了5个set的API分别是corePoolSize, MaximumPoolSize, KeepAliveTime, ThreadFactory, RejectedExecutionHandler.
- 然后我们将这个线程池封装成在我们自己实现的一个类里面,并提供外部修改的接口
@Slf4j
public class DynamicThreadPool {
/**
* 默认核心线程数:5
*/
private static final int CORE_POOL_SIZE = 5;
/**
* 默认最大线程数:10
*/
private static final int MAX_POOL_SIZE = 10;
/**
* 默认队列容量:100
*/
private static final int QUEUE_CAPACITY = 100;
/**
* 默认额外空闲线程存活时间
*/
private static final Long KEEP_ALIVE_TIME = 10L;
/**
* 线程池
*/
private ThreadPoolExecutor threadPool ;
public ThreadPoolExecutor getThreadPool(){
return this.threadPool;
}
//构造默认参数的线程池
private DynamicThreadPool(){
this.threadPool = new ThreadPoolExecutor(
CORE_POOL_SIZE,
MAX_POOL_SIZE,
KEEP_ALIVE_TIME,
TimeUnit.SECONDS,
new FixArrayBlockingQueue<>(QUEUE_CAPACITY),
new ThreadPoolExecutor.CallerRunsPolicy());
}
/**
* Lazy load单例线程池
* 利用JVM底层保证单例
*/
private static class Singleton{
private static DynamicThreadPool instance;
static{
instance = new DynamicThreadPool();
}
public static DynamicThreadPool getInstance(){
return instance;
}
}
/**
* 单例
* @return
*/
public static DynamicThreadPool getDynamicThreadPool() {
return Singleton.getInstance();
}
/**
* 初始化的便捷方法
*/
public static void init(){
getDynamicThreadPool();
}
//暂时省略下列代码,待会往下再贴出
}
首先制定好默认的初始化参数,然后写成一个单例模式,确保不会被创建两次。
下一步则是提供修改线程池的对外方法接口
/**
* 动态设置核心线程数
*/
public ServiceResponse setCorePoolSize(int corePoolSize){
try{
//动态设置核心线程数
this.getThreadPool()
.setCorePoolSize(corePoolSize);
log.info(