从一条阿里编码规范谈线程池的使用

最近在看阿里Java编程规范,有一条引起了我的注意:

【强制】线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
说明:Executors 返回的线程池对象的弊端如下:

  1. FixedThreadPoolSingleThreadPool: 允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。
  2. CachedThreadPoolScheduledThreadPool: 允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。

平时没怎么注意这一点,一般用的多的还是FixedThreadPoolSingleThreadPool。那怎么理解这条规范呢?首先,ThreadPoolExecutor是更底层的类,直接用它的构造方法,可以让我们对创建的线程池有更强的控制。

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          RejectedExecutionHandler handler) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
         Executors.defaultThreadFactory(), handler);
}

我们来看下ThreadPoolExecutor的参数设定:

  • corePoolSize:核心线程数(就算有空闲线程,也不会低于这个数)
  • maximumPoolSize:最大线程数
  • keepAliveTime:最大存活时间(超过corePoolSize数量的线程空闲下最大存活时间)
  • unit:时间单位
  • workQueue:工作队列(核心线程满后,任务会进入这里)
  • handler:任务满负荷(超出最大线程数和工作队列上限之和)后的处理策略

其中处理策略有四种:

  • AbortPolicy:默认策略,在需要拒绝任务时抛出RejectedExecutionException
  • CallerRunsPolicy:直接在 execute 方法的调用线程中运行被拒绝的任务,如果线程池已经关闭,任务将被丢弃
  • DiscardPolicy:直接丢弃任务
  • DiscardOldestPolicy:丢弃队列中等待时间最长的任务,并执行当前提交的任务,如果线程池已经关闭,任务将被丢弃

除此之外我们也可以自定义处理策略。

作为对比,我们看下FixedThreadPool的实现:

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

可见它实际上就是个简化版的ThreadPoolExecutor,通过固定线程数,然后指定工作队列长度为无限(不传长度代表容量无限)。这样确实可能会造成任务无限堆积,引起OOM的问题。所以阿里的规范建议我们直接使用更底层的ThreadPoolExecutor,把处理策略之类的都提前设定好。

不过规范也不是死的,在实际情况中也无法避免使用FixedThreadPool等更高层的实现。一方面是因为使用起来更加方便,另一方面也是有时候使用ThreadPoolExecutor并没有明显的好处。例如:线程池中分配的任务都是关键任务,无法被丢弃,然后因为性能考虑也无法被execute线程同步执行,这样就很难定义一个合适的处理策略,不如直接使用FixedThreadPool。就算有OOM的风险,那也只能说在多种风险权衡下做的一个评估和取舍。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值