Dubbo 线程池
Dubbo 线程模型文章提到,处理请求分为IO 线程和业务线程,
Dubbo 线程池策略主要针对业务线程池,Dubbo 内部给我们实现了
四种fixed、cached、limited、eager线程池,默认是fixed。
Dubbo 线程池,主要还是基于JDK线程池几个参数做文章。
- 核心线程池数
- 最大线程池数
- keep alive时间
- 等待队列
@SPI("fixed")
public interface ThreadPool {
/**
* Thread pool
*
* @param url URL contains thread parameter
* @return thread pool
*/
@Adaptive({THREADPOOL_KEY})
Executor getExecutor(URL url);
}
fixed=org.apache.dubbo.common.threadpool.support.fixed.FixedThreadPool
cached=org.apache.dubbo.common.threadpool.support.cached.CachedThreadPool
limited=org.apache.dubbo.common.threadpool.support.limited.LimitedThreadPool
eager=org.apache.dubbo.common.threadpool.support.eager.EagerThreadPool
fixed 线程池
线程池数固定,最大线程池数等于核心线程池数,因此线程数达到核心线程池数时不会再额外开启线程,
-
keepAlive 时间设置为0,因为不会用到(线程不会超过核心线程池数)
-
queues == 0 时 使用的 SynchronousQueue(默认)
它是个零容量BlockQueue :SynchronousQueue内部并不存储任何元素,即它的容量为0。
也就意味着,当一个线程执行插入操作(put)时,它必须等待另一个线程执行对应的删除操作(take),反之亦然。这种机制确保了数据的直接传递,减少了数据在队列中的等待时间。
- 其他情况使用 LinkedBlockingQueue
public class FixedThreadPool implements ThreadPool {
@Override
public Executor getExecutor(URL url) {
String name = url.getParameter(THREAD_NAME_KEY, DEFAULT_THREAD_NAME);
int threads = url.getParameter(THREADS_KEY, DEFAULT_THREADS);
int queues = url.getParameter(QUEUES_KEY, DEFAULT_QUEUES);
return new ThreadPoolExecutor(threads, threads, 0, TimeUnit.MILLISECONDS,
queues == 0 ? new SynchronousQueue<Runnable>() :
(queues < 0 ? new LinkedBlockingQueue<Runnable>()
: new LinkedBlockingQueue<Runnable>(queues)),
new NamedInternalThreadFactory(name, true), new AbortPolicyWithReport(name, url));
}
}
EagerThreadPool
默认DEFAULT_QUEUES = 0;
默认的TaskQueue 大小为0 。
当线程池线程数达核心线程数时,此时尝试开启新线程执行任务。(因为TaskQueue大小为0,等同于没有等待队列,直接开启新线程执行)
public class EagerThreadPool implements ThreadPool {
@Override
public Executor getExecutor(URL url) {
String name = url.getParameter(THREAD_NAME_KEY, DEFAULT_THREAD_NAME);
int cores = url.getParameter(CORE_THREADS_KEY, DEFAULT_CORE_THREADS);
int threads = url.getParameter(THREADS_KEY, Integer.MAX_VALUE);
int queues = url.getParameter(QUEUES_KEY, DEFAULT_QUEUES);
int alive = url.getParameter(ALIVE_KEY, DEFAULT_ALIVE);
// init queue and executor
TaskQueue<Runnable> taskQueue = new TaskQueue<Runnable>(queues <= 0 ? 1 : queues);
EagerThreadPoolExecutor executor = new EagerThreadPoolExecutor(cores,
threads,
alive,
TimeUnit.MILLISECONDS,
taskQueue,
new NamedInternalThreadFactory(name, true),
new AbortPolicyWithReport(name, url));
taskQueue.setExecutor(executor);
return executor;
}
}
LimitedThreadPool
keepAlive time 是 Long.MAX_VALUE ,
相当于线程一直不会回收,当等待队列满了,就会开启新线程,并且新开启的线程不会被回收,
线程池数量不断动态增加,直到达到最大线程池数。
public class LimitedThreadPool implements ThreadPool {
@Override
public Executor getExecutor(URL url) {
String name = url.getParameter(THREAD_NAME_KEY, DEFAULT_THREAD_NAME);
int cores = url.getParameter(CORE_THREADS_KEY, DEFAULT_CORE_THREADS);
int threads = url.getParameter(THREADS_KEY, DEFAULT_THREADS);
int queues = url.getParameter(QUEUES_KEY, DEFAULT_QUEUES);
return new ThreadPoolExecutor(cores, threads, Long.MAX_VALUE, TimeUnit.MILLISECONDS,
queues == 0 ? new SynchronousQueue<Runnable>() :
(queues < 0 ? new LinkedBlockingQueue<Runnable>()
: new LinkedBlockingQueue<Runnable>(queues)),
new NamedInternalThreadFactory(name, true), new AbortPolicyWithReport(name, url));
}
}
CachedThreadPool
DEFAULT_CORE_THREADS = 0;
DEFAULT_QUEUES = 0;
DEFAULT_ALIVE = 60 * 1000
默认核心线程池数为0, 阻塞队列大小也为0 ,keepAlive 时间默认 1分钟。
新请求到来,由于核心线程为0,且队列大小为0 ,因此会直接开启新线程执行, 当达到keepAlive后会自动被回收。
public class public class CachedThreadPool implements ThreadPool {
@Override
public Executor getExecutor(URL url) {
String name = url.getParameter(THREAD_NAME_KEY, DEFAULT_THREAD_NAME);
int cores = url.getParameter(CORE_THREADS_KEY, DEFAULT_CORE_THREADS);
int threads = url.getParameter(THREADS_KEY, Integer.MAX_VALUE);
int queues = url.getParameter(QUEUES_KEY, DEFAULT_QUEUES);
int alive = url.getParameter(ALIVE_KEY, DEFAULT_ALIVE);
return new ThreadPoolExecutor(cores, threads, alive, TimeUnit.MILLISECONDS,
queues == 0 ? new SynchronousQueue<Runnable>() :
(queues < 0 ? new LinkedBlockingQueue<Runnable>()
: new LinkedBlockingQueue<Runnable>(queues)),
new NamedInternalThreadFactory(name, true), new AbortPolicyWithReport(name, url));
}
}
@Override
public Executor getExecutor(URL url) {
String name = url.getParameter(THREAD_NAME_KEY, DEFAULT_THREAD_NAME);
int cores = url.getParameter(CORE_THREADS_KEY, DEFAULT_CORE_THREADS);
int threads = url.getParameter(THREADS_KEY, Integer.MAX_VALUE);
int queues = url.getParameter(QUEUES_KEY, DEFAULT_QUEUES);
int alive = url.getParameter(ALIVE_KEY, DEFAULT_ALIVE);
return new ThreadPoolExecutor(cores, threads, alive, TimeUnit.MILLISECONDS,
queues == 0 ? new SynchronousQueue<Runnable>() :
(queues < 0 ? new LinkedBlockingQueue<Runnable>()
: new LinkedBlockingQueue<Runnable>(queues)),
new NamedInternalThreadFactory(name, true), new AbortPolicyWithReport(name, url));
}
}
总结
Dubbo 线程池,主要还是基于JDK线程池几个参数做文章,并没有发明什么新东西,因此理解Dubbo 线程池前提掌握jdk 线程池的工作原理,当然也可以自定义扩展实现。 指定线程池方式如下
<dubbo:protocol threadpool="xxx" />
<dubbo:provider threadpool="xxx" />