0 概述
在实际工作中,经常会用到线程池,那么如何设置线程池队列长度,如果长度设置的不合理就无法发挥出多线程的威力。那么队列长度究竟应该设置多大呢?其实要取决于使用场景;比如你是全程异步的系统你的队列设置为0,corePoolSize设置为cpu核数。本文主要通过研究tomcat、Dubbo等业界成熟的产品是如何设置线程队列的,然后分析究竟如何合理的设置线程池队列长度。
1 JDK线程池策略
先增加线程至corePoolSize,之后放入队列,如队列满则增加线程至maximumPoolSize。具体可以参考:JDK线程池源码分析
其实我们不难发现如何队列长度设置无限长度,那么线程池个数将只会增加到corePoolSize
,如果corePoolSize个数设置又过小,这样就会无法发挥出多线程的威力。
2 Tomcat线程池策略
Tomcat的线程池队列是无限长度的,但是线程池会一直创建到maximumPoolSize,然后才把请求放入等待队列中
tomcat 任务队列其继承与LinkedBlockingQueue,覆写offer方法。
@Override
public boolean offer(Runnable o) {
//we can't do any checks
if (parent==null) return (o);
//we are maxed out on threads, simply queue the object
if (() == ()) return (o);
//we have idle threads, just add it to the queue
if (()<(())) return (o);
//线程个数小于MaximumPoolSize会创建新的线程。
//if we have less threads than maximum force creation of a new thread
if (()<()) return false;
//if we reached here, we need to add it to the queue
return (o);
}
2 Dubbo线程池策略
Dubbo 提供3种线程池模型即:FixedThreadPool、CachedThreadPool(客户端默认的)、LimitedThreadPool(服务端默认的),从源码可以看出,其默认的队列长度都是0,当队列长度为0 ,其使用是无缓冲的队列SynchronousQueue,当运行线程超过maximumPoolSize则拒绝请求。
/**
* 此线程池启动时即创建固定大小的线程数,不做任何伸缩,来源于:<code>()</code>
*
* @author
* @see #newFixedThreadPool(int)
*/
public class FixedThreadPool implements ThreadPool {
public Executor getExecutor(URL url) {
String name = (Constants.THREAD_NAME_KEY, Constants.DEFAULT_THREAD_NAME);
int threads = (Constants.THREADS_KEY, Constants.DEFAULT_THREADS);
//默认队列长度为0
int queues = (Constants.QUEUES_KEY, Constants.DEFAULT_QUEUES);
return new ThreadPoolExecutor(threads, threads, 0, ,
queues == 0 ? new SynchronousQueue<Runnable>() :
(queues < 0 ? new LinkedBlockingQueue<Runnable>()
: new LinkedBlockingQueue<Runnable>(queues)),
new NamedThreadFactory(name, true), new AbortPolicyWithReport(name, url));
}
}
/**
* 此线程池一直增长,直到上限,增长后不收缩。
*
* @author <a href="mailto:@">kimi</a>
*/
public class LimitedThreadPool implements ThreadPool {
public Executor getExecutor(URL url) {
String name = (Constants.THREAD_NAME_KEY, Constants.DEFAULT_THREAD_NAME);
int cores = (Constants.CORE_THREADS_KEY, Constants.DEFAULT_CORE_THREADS);
int threads = (Constants.THREADS_KEY, Constants.DEFAULT_THREADS);
//默认队列长度为0
int queues = (Constants.QUEUES_KEY, Constants.DEFAULT_QUEUES);
return new ThreadPoolExecutor(cores, threads, Long.MAX_VALUE, ,
queues == 0 ? new SynchronousQueue<Runnable>() :
(queues < 0 ? new LinkedBlockingQueue<Runnable>()
: new LinkedBlockingQueue<Runnable>(queues)),
new NamedThreadFactory(name, true), new AbortPolicyWithReport(name, url));
}
}
/**
* 此线程池可伸缩,线程空闲一分钟后回收,新请求重新创建线程,来源于:<code>()</code>
*
* @author
* @see #newCachedThreadPool()
*/
public class CachedThreadPool implements ThreadPool {
public Executor getExecutor(URL url) {
String name = (Constants.THREAD_NAME_KEY, Constants.DEFAULT_THREAD_NAME);
int cores = (Constants.CORE_THREADS_KEY, Constants.DEFAULT_CORE_THREADS);
int threads = (Constants.THREADS_KEY, Integer.MAX_VALUE);
//默认队列长度为0
int queues = (Constants.QUEUES_KEY, Constants.DEFAULT_QUEUES);
int alive = (Constants.ALIVE_KEY, Constants.DEFAULT_ALIVE);
return new ThreadPoolExecutor(cores, threads, alive, ,
queues == 0 ? new SynchronousQueue<Runnable>() :
(queues < 0 ? new LinkedBlockingQueue<Runnable>()
: new LinkedBlockingQueue<Runnable>(queues)),
new NamedThreadFactory(name, true), new AbortPolicyWithReport(name, url));
}
}
3 总结
- 线程池的任务队列本来起缓冲作用,但是如果设置的不合理会导致线程池无法扩容至max,这样无法发挥多线程的能力,导致一些服务响应变慢。
- 队列长度要看具体使用场景,取决服务端处理能力以及客户端能容忍的超时时间等
- 建议采用tomcat的处理方式,core与max一致,先扩容到max再放队列,不过队列长度要根据使用场景设置一个上限值,如果响应时间要求较高的系统可以设置为0。