ThreadPoolExcutor线程池使用总结

1、背景: 

在《阿里巴巴java开发手册》中指出了线程资源必须通过线程池提供,不允许在应用中自行显示的创建线程,这样一方面是线程的创建更加规范,可以合理控制开辟线程的数量;另一方面线程的细节管理交给线程池处理,优化了资源的开销。而线程池不允许使用Executors去创建,而要通过ThreadPoolExecutor方式,这一方面是由于jdk中Executor框架虽然提供了如newFixedThreadPool()、newSingleThreadExecutor()、newCachedThreadPool()等创建线程池的方法,但都有其局限性,不够灵活【消耗内存等】;另外由于前面几种方法内部也是通过ThreadPoolExecutor方式实现,使用ThreadPoolExecutor有助于大家明确线程池的运行规则,创建符合自己的业务场景需要的线程池,避免资源耗尽的风险,所以阿里巴巴java开发规范线程池首选ThreadPoolExcutor。

2、线程池的创建

private static final ThreadPoolExecutor THREADPOOL =  new ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,long keepAliveTime, TimeUnit unit,BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler)

     corePoolSize:      线程池维护线程的最少数量 (core : 核心)
     maximumPoolSize:   线程池维护线程的最大数量 
     keepAliveTime:     线程池维护线程所允许的空闲时间
     unit:               线程池维护线程所允许的空闲时间的单位
     workQueue:          线程池所使用的缓冲队列
     handler:            线程池对拒绝任务的处理策略

3、ThreadPoolExcutor内部执行流程

    通过 execute(Runnable)方法被添加到线程池,任务就是一个 Runnable类型的对象,任务的执行方法就是 Runnable类型对象的run()方法。

    当一个任务通过execute(Runnable)方法欲添加到线程池时:

    如果此时线程池中的数量小于corePoolSize,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。

    如果此时线程池中的数量等于 corePoolSize,但是缓冲队列 workQueue未满,那么任务被放入缓冲队列。

    如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量小于maximumPoolSize,建新的线程来处理被添加的任务。

    如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等于maximumPoolSize,那么通过 handler所指定的策略来处理此任务。

    也就是:处理任务的优先级为:

    核心线程corePoolSize、任务队列workQueue、最大线程maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。

    当线程池中的线程数量大于 corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终止。这样,线程池可以动态的调整池中的线程数。

    unit可选的参数为java.util.concurrent.TimeUnit中的几个静态属性:NANOSECONDS、MICROSECONDS、MILLISECONDS、SECONDS。

     workQueue常用的是:java.util.concurrent.ArrayBlockingQueue
     handler有四个选择:
          ThreadPoolExecutor.AbortPolicy():     抛出java.util.concurrent.RejectedExecutionException异常
          ThreadPoolExecutor.CallerRunsPolicy():     重试添加当前的任务,他会自动重复调用execute()方法

          ThreadPoolExecutor.DiscardOldestPolicy():     抛弃旧的任务

          ThreadPoolExecutor.DiscardPolicy():     抛弃当前的任务

4、线程池的使用场合:     

     (1)单个任务处理的时间比较短;

     (2)需要处理的任务数量大

5、使用案例:这里以发短信功能为例

private static final ThreadPoolExecutor THREADPOOL = new ThreadPoolExecutor(2, 4, 3,
        TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(3),
        new ThreadPoolExecutor.DiscardOldestPolicy());
/**
 * 发送短信
 *
 * @param dcConsigneeInfo
 * @param consigneeCode
 * @param date
 */
private void sendMiaoxinSms(DcConsigneeInfo dcConsigneeInfo, String consigneeCode, Date date) {
    if (dcConsigneeInfo != null) {
        log.info("调用短信接口");
        THREADPOOL.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    miaoxinSmsUtils.send(dcConsigneeInfo.getConsigneePhone(),     
                      miaoxinSmsUtils.getMsgInfo(consigneeCode, date));                       
                } catch (Exception e) {
                    log.error("调用发送短信接口出现异常:" + dcConsigneeInfo.getConsigneePhone(), e);
                }
            }
        });

    }
}

 

  • 9
    点赞
  • 68
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值