线程池的用法及思考

Posted cnxieyang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程池的用法及思考相关的知识,希望对你有一定的参考价值。

本文介绍下Java中线程池的基本用法,基于此说明如何去确定线程池的大小。

线程池的创建方法

  newFixedThreadPool

   创建固定线程数的线程池,见下创建代码

  

/**
     * Creates a thread pool that reuses a fixed number of threads
     * operating off a shared unbounded queue.  At any point, at most
     * {@code nThreads} threads will be active processing tasks.
     * If additional tasks are submitted when all threads are active,
     * they will wait in the queue until a thread is available.
     * If any thread terminates due to a failure during execution
     * prior to shutdown, a new one will take its place if needed to
     * execute subsequent tasks.  The threads in the pool will exist
     * until it is explicitly {@link ExecutorService#shutdown shutdown}.
     *
     * @param nThreads the number of threads in the pool
     * @return the newly created thread pool
     * @throws IllegalArgumentException if {@code nThreads <= 0}
     */
    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

    从代码中可发现,corePoolSize和maxPoolSize都是相等的,取决于传入的线程数,keepAliveTime=0代表线程不进行超时回收,但使用的是无界队列,当任务数量过多时,将会导致OOM溢出。

  newSingleThreadPool

  创建线程数为1的线程池,创建代码如下。

  

 /**
     * Creates an Executor that uses a single worker thread operating
     * off an unbounded queue. (Note however that if this single
     * thread terminates due to a failure during execution prior to
     * shutdown, a new one will take its place if needed to execute
     * subsequent tasks.)  Tasks are guaranteed to execute
     * sequentially, and no more than one task will be active at any
     * given time. Unlike the otherwise equivalent
     * {@code newFixedThreadPool(1)} the returned executor is
     * guaranteed not to be reconfigurable to use additional threads.
     *
     * @return the newly created single-threaded Executor
     */
    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }


/**
    * 创建线程数为1的线程池
    *
    */

  我们发现corePoolSize和MaxPoolSize都是1,使用的还是无界队列,存在OOM

  newCachedThreadPool

  创建可缓存的线程池。代码如下

  

  /**
     * Creates a thread pool that creates new threads as needed, but
     * will reuse previously constructed threads when they are
     * available.  These pools will typically improve the performance
     * of programs that execute many short-lived asynchronous tasks.
     * Calls to {@code execute} will reuse previously constructed
     * threads if available. If no existing thread is available, a new
     * thread will be created and added to the pool. Threads that have
     * not been used for sixty seconds are terminated and removed from
     * the cache. Thus, a pool that remains idle for long enough will
     * not consume any resources. Note that pools with similar
     * properties but different details (for example, timeout parameters)
     * may be created using {@link ThreadPoolExecutor} constructors.
     *
     * @return the newly created thread pool
     */
    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());

   从创建代码中发现,corePoolSize核心线程数在一定时间内可以为零,当有一个新的任务时,只需要创建一个存活周期为60秒的线程,使用的是直接队列,队列任务为零,当任务过多时,会创建大量的线程,仍然会导致溢出。

  newScheduledThreadPool

  创建定义任务相关的线程数,在普通线程池的基础上引入了定时任务相关的操作。

  

 /**
     * Creates a new {@code ScheduledThreadPoolExecutor} with the
     * given core pool size.
     *
     * @param corePoolSize the number of threads to keep in the pool, even
     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
     * @throws IllegalArgumentException if {@code corePoolSize < 0}
     */
    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }

  我们发现可以指定核心线程数,maxPoolSize为Integer.MAX_VALUE,非核心线程数不进行回收,使用了延迟队列,也存在OOM

 

  workStealingPool

  jdk1.8新增的。产生递归操作时,可使用此线程池。

 

  综上所述,提供了多种创建线程池的方法,具体使用哪种线程池方法,需要根据实际情况来定,使用多少线程数,最后通过性能测试去确定,我们也可以从CPU密集型和IO密集型方面进行简易区分。CPU密集型的线程数为CPU核心数的1到2倍。IO密集型线程数可为CPU核心数的10倍左右。

  参考计算方法为:线程数=cpu核心数 * (1+ 平均等待时间/平均运行时间)

  

以上是关于线程池的用法及思考的主要内容,如果未能解决你的问题,请参考以下文章

浅聊JAVA 线程池的一般用法

IDEA对新建java线程池的建议

Spring中线程池的用法

Java 13都发布了,线程池的正确用法你知道吗?

newCacheThreadPool()newFixedThreadPool()newScheduledThreadPool()newSingleThreadExecutor()自定义线程池(代码片段

Java线程池详解