7.线程池中的阻塞队列无限大是否合适

      在设置线程池队列长度时,如果长度设置的不合理就无法发挥出多线程的威力。设置线程池的队列长度取决于使用场景;比如全程异步的系统,队列可以设置为0,corePoolSize设置为cpu核数。研究tomcat、Dubbo等业界成熟的产品是如何设置线程队列,分析如何合理设置线程池队列长度。

1.JDK线程池策略

      先增加线程至corePoolSize,之后放入队列,如果队列满则增加线程至maximumPoolSize。其实我们不难发现如果队列长度设置无限长度,那么线程池个数将只会增加到corePoolSize,如果corePoolSize个数设置又过小,这样就会无法发挥出多线程的威力。

2.Tomcat线程池策略

Tomcat的线程池队列是无限长度的,但是线程池会一直创建到maximumPoolSize,然后才把请求放入等待队列中

tomcat 任务队列org.apache.tomcat.util.threads.TaskQueue其继承与LinkedBlockingQueue,覆写offer方法。 

@Override
    public boolean offer(Runnable o) {
      //we can't do any checks
        if (parent==null) return super.offer(o);
        //we are maxed out on threads, simply queue the object
        if (parent.getPoolSize() == parent.getMaximumPoolSize()) return super.offer(o);
        //we have idle threads, just add it to the queue
        if (parent.getSubmittedCount()<(parent.getPoolSize())) return super.offer(o);
         //线程个数小于MaximumPoolSize会创建新的线程。
        //if we have less threads than maximum force creation of a new thread
        if (parent.getPoolSize()         //if we reached here, we need to add it to the queue
        return super.offer(o);
    }

3.Dubbo线程池策略

        Dubbo 提供3种线程池模型即:FixedThreadPool、CachedThreadPool(客户端默认的)、LimitedThreadPool(服务端默认的),从源码可以看出,其默认的队列长度都是0,当队列长度为0 ,其使用是无缓冲的队列SynchronousQueue,当运行线程超过maximumPoolSize则拒绝请求。 

/**
     * 此线程池启动时即创建固定大小的线程数,不做任何伸缩,来源于:Executors.newFixedThreadPool()
     *
     * @author william.liangf
     * @see java.util.concurrent.Executors#newFixedThreadPool(int)
     */
    public class FixedThreadPool implements ThreadPool {

        public Executor getExecutor(URL url) {
            String name = url.getParameter(Constants.THREAD_NAME_KEY, Constants.DEFAULT_THREAD_NAME);
            int threads = url.getParameter(Constants.THREADS_KEY, Constants.DEFAULT_THREADS);
            //默认队列长度为0
            int queues = url.getParameter(Constants.QUEUES_KEY, Constants.DEFAULT_QUEUES);
            return new ThreadPoolExecutor(threads, threads, 0, TimeUnit.MILLISECONDS,
                    queues == 0 ? new SynchronousQueue() :
                            (queues < 0 ? new LinkedBlockingQueue()
                                    : new LinkedBlockingQueue(queues)),
                    new NamedThreadFactory(name, true), new AbortPolicyWithReport(name, url));
        }

    }

    /**
     * 此线程池一直增长,直到上限,增长后不收缩。
     *
     * @author kimi
     */
    public class LimitedThreadPool implements ThreadPool {

        public Executor getExecutor(URL url) {
            String name = url.getParameter(Constants.THREAD_NAME_KEY, Constants.DEFAULT_THREAD_NAME);
            int cores = url.getParameter(Constants.CORE_THREADS_KEY, Constants.DEFAULT_CORE_THREADS);
            int threads = url.getParameter(Constants.THREADS_KEY, Constants.DEFAULT_THREADS);
                 //默认队列长度为0
            int queues = url.getParameter(Constants.QUEUES_KEY, Constants.DEFAULT_QUEUES);
            return new ThreadPoolExecutor(cores, threads, Long.MAX_VALUE, TimeUnit.MILLISECONDS,
                    queues == 0 ? new SynchronousQueue() :
                            (queues < 0 ? new LinkedBlockingQueue()
                                    : new LinkedBlockingQueue(queues)),
                    new NamedThreadFactory(name, true), new AbortPolicyWithReport(name, url));
        }

    }

    /**
     * 此线程池可伸缩,线程空闲一分钟后回收,新请求重新创建线程,来源于:Executors.newCachedThreadPool()
     *
     * @author william.liangf
     * @see java.util.concurrent.Executors#newCachedThreadPool()
     */
    public class CachedThreadPool implements ThreadPool {

        public Executor getExecutor(URL url) {
            String name = url.getParameter(Constants.THREAD_NAME_KEY, Constants.DEFAULT_THREAD_NAME);
            int cores = url.getParameter(Constants.CORE_THREADS_KEY, Constants.DEFAULT_CORE_THREADS);
            int threads = url.getParameter(Constants.THREADS_KEY, Integer.MAX_VALUE);
                 //默认队列长度为0
            int queues = url.getParameter(Constants.QUEUES_KEY, Constants.DEFAULT_QUEUES);
            int alive = url.getParameter(Constants.ALIVE_KEY, Constants.DEFAULT_ALIVE);
            return new ThreadPoolExecutor(cores, threads, alive, TimeUnit.MILLISECONDS,
                    queues == 0 ? new SynchronousQueue() :
                            (queues < 0 ? new LinkedBlockingQueue()
                                    : new LinkedBlockingQueue(queues)),
                    new NamedThreadFactory(name, true), new AbortPolicyWithReport(name, url));
        }

    }

总结

       线程池的任务队列本来起缓冲作用,但是如果设置的不合理会导致线程池无法扩容至max,这样无法发挥多线程的能力,导致一些服务响应变慢。

       队列长度要看具体使用场景,取决服务端处理能力以及客户端能容忍的超时时间等

       建议采用tomcat的处理方式,core与max一致,先扩容到max再放队列,不过队列长度要根据使用场景设置一个上限值,如果响应时间要求较高的系统可以设置为0。

 

你可能感兴趣的:(线程)