java使用Executors创建的线程池的特点分析

在使用java线程池时,我们都习惯于使用Executors来创建线程池,常见的线程池有:

  • newFixedThreadPool
  • newSingleThreadExecutor
  • newCachedThreadPool

而这些线程池其实都是使用ThreadPoolExecutor来创建的,其主要构造参数:

  • corePoolSize
    核心线程数
  • maximumPoolSize
    最大线程数
  • keepAliveTime
    线程最大闲置时间
  • workQueue
    存放等待运行任务的队列

任务提交时线程是的运行机制:
当向线程池提交任务时,首先看线程池是否有空闲线程,如果有就将任务分配到一个空闲线程中运行。
而如果没有,则要看当前正在运行的线程数大小情况,如果当前正在运行的线程数小于corePoolSize,那么就直接创建一个新线程,然后将任务分配给此线程运行。
而如果当前线程数已达到corePoolSize,那么则需要将此任务存放到workQueue里,等待空闲线程来运行此任务。
而如果workQueue队列也满了,那么则又需要查看当前线程数是否小于maximumPoolSize,如果小于maximumPoolSize,那么就直接创建一个新线程去运行此任务,否则此时线程数已到达maximumPoolSize,并且workQueue队列也满了,就会报RejectedExecutionExecption错误。

当线程池中的很多空闲的线程,并且总的线程数超过了corePoolSize时,则如果某个线程空闲的时间超过了keepAliveTime,则会此线程终止。
在这里插入图片描述

理解了ThreadPoolExecutor的各个参数后,现在回头再分析下Executors创建的各个线程池的特点:

  • newFixedThreadPool
return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>(),
                                      threadFactory);

corePoolSize和maximumPoolSize为用户指定的值nThreads,意味着线程中的最大线程数为用户指定的nThreads。workQueue为LinkedBlockingQueue的无界队列,即没有大小限制。所以,此线程池中的线程数最多为一个,但是可以无限向线程池中提交任务而不报错,只是这些任务会被存放在workQueue中等待运行,这样很有可能造成workQueue的元素不断增多,导致OutOfMemeory。

  • newSingleThreadExecutor
new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));

corePoolSize和maximumPoolSize为1,workQueue为LinkedBlockingQueue的无界队列,即没有大小限制。这么看来newSingleThreadExecutor只是newFixedThreadPool的一个特列,只是最大线程数为1而已,它同样也会有workQueue无限大,导致的OutOfMemeory问题。

  • newCachedThreadPool
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());

corePoolSize为0,maximumPoolSize为整型的最大值,这意味线程池中可以最多创建整型的最大值数量的线程,某种程度上可以视为没有数量限制。workQueue为SynchronousQueue队列,此队列可以想象成长度为0的队列,这意味着当线程池中的线程不够时,任务不会存在workQueue队列中,等待空闲的线程来运行它,而是直接要么报RejectedExecutionException,要么创建新的线程来运行它,而maximumPoolSize很大,几乎不会限制创建线程的数量,因而会直接创建线程来运行它。在大量任务并发提交时,很有可能造成线程池中创建的线程数量过多,从而导致OutOfMemory,因为创建线程需要堆栈内存。

所以,在使用Executors来创建线程池时,我们一定要弄清楚所创建的线程池的特点,否则可能会出现很多意想不到的问题。只有弄清楚各个线程池的特点,我们才能根据各个场景更好的选择使用哪个线程池,从而规避问题。
其实在使用线程池时,我们最好尝试使用ThreadPoolExecutor来创建,一方面我们可以控制线程池的各个参数,另一方面也便于我们更好的理解线程池的运行机制。

Executors中还有其他类型的一些线程池,但都逃不了ThreadPoolExecutor,可以试着使用上面的方法去分析下这些线程池的特点。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值