dubbo的线程池

之前线上代码Xstream代码的GC问题,导致dubbo服务访问的时候,出现线程不足,无法处理业务线程。因为出现了这个问题,我就看了看dubbo线程池。

1.介绍

当我们在使用dubbo的时候,是可以通过调整线程池来达到调优的效果,我们可以在dubbo:protocol 标签中使用用threadpool属性选择自己想要使用的线程池,通过threads属性配置服务线程数,queues属性配置使用的队列。例如:

 <dubbo:protocol  name="dubbo"  threadpool="fixed"  queues="100"  threads="100"/>

dubbo的官网地址:http://dubbo.apache.org/

dubbo官网里面有源码介绍http://dubbo.apache.org/zh/docs/v2.7/dev/,还有博客地址http://dubbo.apache.org/zh/blog/news/,都是不错的内容。

dubbo的线程池在dubbo的org.apache.dubbo.common.threadpool包下面:

在这里插入图片描述

2.ThreadPool接口

/**
 * ThreadPool
 */
@SPI("fixed")
public interface ThreadPool {

    /**
     * Thread pool
     *
     * @param url URL contains thread parameter
     * @return thread pool
     */
    @Adaptive({THREADPOOL_KEY})
    Executor getExecutor(URL url);

}

我们可以看到ThreadPool接口是个扩展点,然后默认实现是fixed,然后里面有个getExecutor方法,被@Adaptive注解修饰。在dubbo中ThreadPool有4个实现类,分别是:

在这里插入图片描述

  1. CachedThreadPool 缓存线程池,超过keepAliveTime时间删除,使用的时候再创建
  2. FixedThreadPool 固定线程数量线程池,一旦建立,一直持有。
  3. LimitedThreadPool 可伸缩线程池,线程只增长不收缩。
  4. EagerThreadPool 当core线程数忙的时候,创建新线程,而不是将任务放入阻塞队列。这个使用自己队列TaskQueue。

3.CachedThreadPool

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));
    }
  1. core:核心线程数,默认是0;
  2. maxThread:最大线程数,默认是Integer.MAX_VALUE,可以看作是无限大。
  3. queues:如果queues=0,使用SynchronousQueue,如果是小于0,就是个new
    LinkedBlockingQueue
    队列,这个队列大小是Integer.MAX_VALUE,这个查看LinkedBlockingQueue源码可以看到。如果是queues大于0
    ,就创建queues大小的LinkedBlockingQueue,默认是0 。
  4. keepalive:最大空闲时间,默认是 60 * 1000ms ,也就是1分钟。
    我们可以看到CachedThreadPool使用默认参数的话,就会无限创建线程,然后超过空闲时间,线程就会被销毁,然后再使用的时候,就会再创建。

4.FixedThreadPool

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));
    }
  1. core:核心线程数,默认是200
  2. maxThreads: 最大线程数。默认是200
  3. queues:当queues<0,使用一个无限大的LinkedBlockingQueue队列,当queues>=0
    的时候创建queues大小的LinkedBlockingQueue。默认是0,也是创建0大小的LinkedBlockingQueue队列。
  4. keepalive:直接就是0,表示不销毁。 我们可以看出FixedThreadPool
    创建固定大小的线程池,默认是200,期间不会销毁,使用了FixedThreadPool线程池,keepalive配置也没有作用。

5.LimitedThreadPool

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));
    }
  1. core:核心线程数,默认是0
  2. maxThreads: 最大线程数,默认是200
  3. queues:当queues=0的时候使用SynchronousQueue,当queues <
    0的时候创建一个无限大小LinkedBlockingQueue队列,当queues>0的时候,创建queues大小的LinkedBlockingQueue队列。默认是0
  4. keepalive:直接就是Long.MAX_VALUE。
    我们可以看到keepalive直接是最大的,也就是线程可以增大,但是不会收缩,原因是防止大流量请求过来,还得现创建线程。

6.EagerThreadPool

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;
    }

EagerThreadPoolExecutor继承ThreadPoolExecutor,重写了ThreadPoolExecutor的afterExecute,execute方法。EagerThreadPoolExecutor中一个AtomicInteger变量submittedTaskCount用于记录线程池正在运行的任务数

Override
    protected void afterExecute(Runnable r, Throwable t) {
    	// 提交任务执行结束,任务数减1
        submittedTaskCount.decrementAndGet();
    }
@Override
    public void execute(Runnable command) {
        if (command == null) {
            throw new NullPointerException();
        }
        // 提交的任务增加1
        submittedTaskCount.incrementAndGet();
        try {
            super.execute(command);
        } catch (RejectedExecutionException rx) {
            // 被线程池策略拒绝,重试机制
            final TaskQueue queue = (TaskQueue) super.getQueue();
            try {
                if (!queue.retryOffer(command, 0, TimeUnit.MILLISECONDS)) {
                	// 队列重试失败,提交任务数减1
                    submittedTaskCount.decrementAndGet();
                    // 抛出Queue capacity is full
                    throw new RejectedExecutionException("Queue capacity is full.", rx);
                }
            } catch (InterruptedException x) {
            	// 线程异常,提交任务数减1
                submittedTaskCount.decrementAndGet();
                throw new RejectedExecutionException(x);
            }
        } catch (Throwable t) {
            // decrease any way
            submittedTaskCount.decrementAndGet();
            throw t;
        }
    }

EagerThreadPool还自定义了自己的线程队列,TaskQueue extends LinkedBlockingQueue,重写了队列的
offer方法。

public boolean offer(Runnable runnable) {
        if (executor == null) {
            throw new RejectedExecutionException("The task queue does not have executor!");
        }

		// 线程池目前运行的线程
        int currentPoolThreadSize = executor.getPoolSize();
        // 提交的任务数小于当前运行的线程数 直接提交就能被消费
        if (executor.getSubmittedTaskCount() < currentPoolThreadSize) {
            return super.offer(runnable);
        }

        // 提交的任务大于当前线程数目,且当前线程数小于最大线程数,等待线程线程创建
        if (currentPoolThreadSize < executor.getMaximumPoolSize()) {
            return false;
        }

        // 当起达到最大线程池提交任务
        return super.offer(runnable);
    }

参考文章:https://blog.csdn.net/yuanshangshenghuo/article/details/106454660

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值