Executor框架

2018-09-12  本文已影响0人  叫我民哥L

Executor框架简介

Executor框架的两级调度模型

Java多线程程序通常把应用分解为若干个任务,然后使用用户级的调度器(Executor框架)将这些任务映射为固定数量的线程;在底层,操作系统内核将这些线程映射到硬件处理器上。被称为两级调度模型。

Executor框架的结构与成员

  1. Executor框架的结构
    Executor框架主要由3大部分组件组成:

ThreadPoolExector详解

关于ThreadPoolExector的4个组件构成已经在java线程池实现原理中介绍过,在此不再重复,下面介绍通过Exectors框架的工具类Exectors可以创建的3种类型的ThreadPoolExector:

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

FixedThreadPool的corePoolSize和maximumPoolSize都被设置为创建FixedThreadPool时指定的参数nThreads。
当线程池中的线程数大于corePoolSize时,keepAliveTime为多余的空闲线程等待新任务的最长时间,超过这个时间后多余的线程将被终止。这里把keepAliveTime设置为0L,意味着多余的空闲线程会被立即终止。
FixedThreadPool使用无界队列LinkedBlockingQueue作为线程池的工作队列(队列的容量为Integer.MAX_VALUE)。使用无界队列作为工作队列会对线程池带来如下影响。

  1. 当线程池中的线程数达到corePoolSize后,新任务将在无界队列中等待,因此线程池中线程数不会超过corePoolSize。
  2. 由于1,使用无界队列时maximumPoolSize将是一个无效参数。
  3. 由于1和2,使用无界队列时keepAliveTime将是一个无效参数。
  4. 由于使用无界队列,运行中的FixedThreadPool(未执行shutDown()或shutDownNow())不会拒绝任务(不会调用RejectedExecutionHandler.rejectedExecution方法)
public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

SingleThreadExecutor的corePoolSize和maximumPoolSize被设置为1.其他参数与FixedThreadPool相同。所以SingleThreadExecutor使用无界队列作为工作队列对线程池带来的影响与FixedThreadPool相同。

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

CachedThreadPool的corePoolSize被设置成0,即corePoolSize为空;maximumPoolSize被设置为Integer.MAX_VALUE,即maximumPool是无界的。这里把keepAliveTime设置为60L,意味着CachedThreadPool中的空闲线程等待任务的最长时间为60s,空闲线程超过60s后将会被终止。
CachedThreadPool使用没有没有容量的SynchronousQueue作为线程池工作队列,但CachedThreadPool的maximumPool是无界的。这意味着,如果主线程提交任务的速度高于maximumPool中线程处理任务的速度时,CachedThreadPool就会不断地创建新任务。极端情况下,CachedThreadPool会因为创建过多线程而耗尽CPU和内存资源。

In The End

对比
corePoolSize maximumPoolSize workQueue keepAliveTime 特点
FixedThreadPool nTread nTread LinkedBlockingQueue 0 不会拒绝任务
SingleThreadExecutor 1 1 LinkedBlockingQueue 0 只有单个worker线程
CachedThreadPool 0 Integer.MAX_VALUE SynchronousQueue 60 使用阻塞队列; maximumPoolSize无界
适用场景

FixedThreadPool:由于FixedThreadPool使用无界队列,所以不会拒绝任务。因此合理设置corePoolSize数量配合任务队列,适用于负载比较重的服务器。
SingleThreadExecutor:SingleThreadExecutor只有一个worker线程,所以提交到SingleThreadExecutor的任务会保证顺序的执行,因此SingleThreadExecutor适用于需要保证顺序的执行任务,并且整个生命周期不会有多个线程的场景。
CachedThreadPool:CachedThreadPool时大小无界的线程池,因此适用于执行很多短期异步任务的小程序,或者是负载较轻的服务器。

上一篇下一篇

猜你喜欢

热点阅读