线程池介绍

概况

  线程池,从字面含义来看,是指管理一组同构工作线程的资源池。线程池是与工作队列密切相关的,其中在工作队列中保存了所有等待执行的任务。工作者线程的任务很简单:从工作队列中获取一个任务,执行任务,然后返回线程池并等待下一个任务。在上一节当中,我们介绍了同步容器及并发容器相关的知识,在最后,我们讲到了阻塞队列这类并发容器。线程池的实现中,工作队列就用到了阻塞队列。
  类库提供了一个灵活的线程池以及一些有用的默认配置,可以通过调用Executors中的静态工行方法之一来创建一个线程池:
这里写图片描述
  从函数名字可以看出,Executors能够创建一下几种类型的线程池:
+ newFixedThreadPool
  创建一个固定长度的线程池,每当提交一个任务时就创建一个线程成,知道达到线程池的最大数量,这是线程池的规模将不再变化
+ newSingleThreadExecutor
  创建一个单线程的线程池。
+ newCachedThreadPool
  创建一个可缓存的线程池,如果线程池当前规模超出了处理器需求,那么将回收空闲的线程,而当需求增加时,则可以添加新的线程,线程池的规模不存在任何限制。
+ ScheduledExecutorService
  创建一个固定长度的线程池,而且以延迟或者定时的方式来执行任务。

  在这几个静态构造函数中,其实实质上都调用了ThreadPoolExecutor类的构造函数来创建一个线程池。我们来看下,包java.util.concurrent下ThreadPoolExecutor类的构造函数:

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
}

  在该构造函数当中,corePoolSize表示线程池中线程的数量,maximumPoolSize表示线程池中最大线程数据,keepAliveTime表示的是,当线程池中的线程数量大于corePoolSize时,闲置线程终结前等待任务分配的最大等待时间(如果超过这个时间线程还没有被分配任务,该线程将终结)。workQueue,handler,threadFactory是线程池的核心内容,我们将具体来讲解一下这三个属性的作用。

工作队列(BlockingQueue)

  首先,来看一下该属性的定义:

/**
 * The queue used for holding tasks and handing off to worker
 * threads.  We do not require that workQueue.poll() returning
 * null necessarily means that workQueue.isEmpty(), so rely
 * solely on isEmpty to see if the queue is empty (which we must
 * do for example when deciding whether to transition from
 * SHUTDOWN to TIDYING).  This accommodates special-purpose
 * queues such as DelayQueues for which poll() is allowed to
 * return null even if it may later return non-null when delays
 * expire.
 */
private final BlockingQueue<Runnable> workQueue;

  BlockingQueue就是在上一篇文中当中介绍到的阻塞队列。具体的实现类,则需要根据具体的业务场景以及其他的配置参数做出选择。从同步容器与并发容器类简介中我们可以知道,阻塞队列可粗分为三类,无界队列,有界队列,以及同步移交(Synchronous Handoff)。对于无界队列,不存在队列的饱和情况,而对于游街队列及同步移交来说,当任务的数量大于固定队列的大小时,如果处理这部分对于的任务,则需要根据饱和策略来决定。

饱和策略(RejectedExecutionHandler)

  当有界队列被填满后,饱和策略开始发挥作用。JDK提供了几种不同的RejectedExecutionHandler实现,每种实现都包含了不同的饱和策略:
+ AbortPolicy
  “中止”策略是默认的饱和策略。该策略将抛出未检查的RejectedExecutionException异常。
+ CallerRunsPolicy
  “调用者运行”策略实现了一种调节机制,该策略既不会抛弃任务,也不会抛出异常,而是将某些任务回退到调用者,从而降低新任务的流量。它不会在线程池的某个线程中执行新提交的任务,而是在一个调用了excute的线程中执行该任务。
+ DiscardPolicy
  当新提交的任务无法保存到队列中等待执行时,“抛弃(Discard)”策略会悄悄抛弃该任务。
+ DiscardOldestPolicy
  “抛弃最旧的”策略会抛弃下一个将被执行的任务。

线程工厂(ThreadFactory)

  每当线程池需要创建一个线程时,都是通过线程工厂方法来完成了。默认的线程工厂将创建一个新的,非守护的线程,并不包含特殊的配置信息。因此,当我没需要创建特殊的线程(不如在创建过程当中打印日志,给线程修改名字)时,就可以提供我们自己的线程工厂实例就可以了。自定义一个线程工厂很简单,只需要实现ThreadFactory接口即可:

public interface ThreadFactory {

    /**
     * Constructs a new {@code Thread}.  Implementations may also initialize
     * priority, name, daemon status, {@code ThreadGroup}, etc.
     *
     * @param r a runnable to be executed by new thread instance
     * @return constructed thread, or {@code null} if the request to
     *         create a thread is rejected
     */
    Thread newThread(Runnable r);
}

  该接口只有一个函数,我们可以通过该函数,定制化我们自己的线程。
  线程池的介绍就到这里,在程序代码中,强烈建议,不要显示地定义线程去执行任务,而是通过线程池来执行任务,防止不可预料的错误发生。

  欢迎关注个人公众号,本公众号用于日常技术分享
这里写图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值