JUC之Executors

在《JUC之ThreadPoolExecutor(1)总体介绍》与《JUC之ThreadPoolExecutor(2)方法介绍》中介绍了ThreadPoolExecutor。使用ThreadPoolExecutor创建线程池,实现线程池的相关功能。

通过继承图可以看到,ThreadPoolExecutor的最顶级父类为接口Executor。因此ThreadPoolExecutor也可以转换成Executor类型。

本文介绍Executors,Executors可以看做是Executor的工作类(可以对比Collection接口与Collections工具类)。在Executors中,借助于ThreadPoolExecutor已经实现了几种不同类型的ThreadPoolExecutor,以便我们方便地在开发中直接使用。通过Executors提供的方法可以很快的创建ThreadPoolExecutor对象。


█ 构造器

private Executors() {}

Executors中的构造器访问权限为private,所以在外部无法正常地通过new Executors()来创建Executors对象。在Executors中的方法都是static静态方法,因此可以直接通过Executors.静态方法来调用,比如:Executors.newSingleThreadExecutor();


不同类型的ExecutorService

Executors提供了多种获取来创建不同类型的ExecutorService。为什么方法返回值不是ThreadPoolExecutor类型,因为ThreadPoolExecutor实现了ExecutorService接口,因此ThreadPoolExecutor也是ExecutorService类型的。而且Executors中创建的线程池不一定是借助了ThreadPoolExecutor,而是依赖于其他的Executor,但他们都有共同的父类ExecutorService。

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

ThreadPoolExecutor的构造器提供了7大核心参数,通过对参数的设置可以实现不同类型的ThreadPoolExecutor。

通过new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());的参数设置可以看出此种类型的ThreadPoolExecutor有以下几种特点:

①核心worker的数量与最大worker的数量相同。

核心worker与最大worker数量相同,而核心worker数量与临时工worker数量相加之和就是最大worker数量。所以,此种类型的ThreadPoolExecutor是只有核心worker,没有临时工worker的。于是当阻塞队列已经满了的时候,是不会创建临时工worker的,而是会直接执行拒绝策略。因为此种类型的ThreadPoolExecutor只创建核心worker,没有临时工worker,而核心worker被创建之后是固定的,不会被回收,因此结合着这个特点,此种类型的ThreadPoolExecutor便是固定大小worker数量的,所以叫newFixedThreadPool,Fixed意思便是固定的。

②空闲时间为0

因为没有临时工worker,所以空闲时间就设置成0即也就相当于和没有设置一样。因为空闲时间是用来设置回收临时工worker的时间,又因为没有临时工worker,因此就不需要回收了,自然这个空闲时间就没有设置意义了。

LinkedBlockingQueue

阻塞队列的类型为LinkedBlockingQueue,LinkedBlockingQueue的特点是使用链表来实现队列的,因为在创建LinkedBlockingQueue的时候并没有指定队列的最大容量(如new LinkedBlockingQueue(100),指定Queue的最大容量为100),因此这里的LinkedBlockingQueue的没有边界的,可以一直往里面添加元素,会造成内存不够用而发生内存溢出的异常,正是存在这个内存问题,所以阿里巴巴技术手册中建议不要直接使用Executors提供的相关方法来创建线程池,而是通过手动构建ThreadPoolExecutor对象来创建线程池,因为手动构建地时候可以设置阻塞队列的最大容量。(关于LinkedBlockingQueue的介绍,请戳《BlockingQueue之LinkedBlockingQueue》)

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

 依然从创建ThreadPoolExecutor对象的传参来看该类型的ThreadPoolExecutor的特点。

①核心worker数为0,最大worker数为Integer.MAX_VALUE。

与newFixedThreadPool刚好相反,此种类型的ThreadPoolExecutor是没有核心worker,只有临时工worker的。因此新提交的任务会先放进阻塞队列中,等阻塞队列满了之后再创建临时worker来执行等待队列中的任务。

②空闲时间为60。

当创建的临时工worker在长达60秒没有执行任务了,线程池便会将该临时工worker回收了。

SynchronousQueue

阻塞队列的类型是SynchronousQueue,SynchronousQueue的具有生产者-消费者模型的特点的阻塞队列,每次队列中只能添加一个元素,当添加一个元素到队列后,只有等该元素被从队列中移出后,才能继续向队列中添加元素。

  • newSingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>(),
                                threadFactory));
}

①核心worker与最大worker数量都为1。

此类型的ThreadPoolExecutor始终只有一个核心worker在执行任务。同时也不会创建临时工worker。

②空闲时间为0。

此设置和newFixedThreadPool含义相同。

③LinkedBlockingQueue

创建的ThreadPoolExecutor,其中的BlockingQueue仍然没有指定最大容量,所以也是没有边界的阻塞队列。

FinalizableDelegatedExecutorService

newSingleThreadExecutor没有直接使用ThreadPoolExecutor,而是在外面又封装了一层FinalizableDelegatedExecutorService。FinalizableDelegatedExecutorService继承自DelegatedExecutorService。DelegatedExecutorService和ThreadPoolExecutor具有相同的父类继承关系。

  • newScheduledThreadPool
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}
public static ScheduledExecutorService newScheduledThreadPool(
        int corePoolSize, ThreadFactory threadFactory) {
    return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
}

ScheduledThreadPoolExecutor具有定时执行任务功能的线程池。

public class ScheduledThreadPoolExecutor
        extends ThreadPoolExecutor
        implements ScheduledExecutorService

ScheduledThreadPoolExecutor继承了ThreadPoolExecutor,因此其具有普通线程池的功能。

public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
          new DelayedWorkQueue());
}

super构造器即调用了ThreadPoolExecutor的构造器。从参数设置上面来看,ScheduledThreadPoolExecutor可以指定核心worker的数量,最大worker数量为Integer.MAX_VALUE,并且阻塞队列类型为DelayedWorkQueue

(关于ScheduledThreadPoolExecutor的具体介绍,将在后续专门写一篇文章来介绍。在此先对它有个简单的印象。)

  • newSingleThreadScheduledExecutor

与newScheduledThreadPool相同,newSingleThreadScheduledExecutor也是具有定时执行任务功能的。只不过不同于newScheduledThreadPool可以设置多个核心worker,newSingleThreadScheduledExecutor只有一个核心worker。

public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
    return new DelegatedScheduledExecutorService
        (new ScheduledThreadPoolExecutor(1));
}
public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
    return new DelegatedScheduledExecutorService
        (new ScheduledThreadPoolExecutor(1, threadFactory));
}

DelegatedScheduledExecutorService:

实现newSingleThreadScheduledExecutor,在外包装了一层DelegatedScheduledExecutorService

  • newWorkStealingPool

可以提供并行运行的线程的线程池。

public static ExecutorService newWorkStealingPool() {
    return new ForkJoinPool
        (Runtime.getRuntime().availableProcessors(),
         ForkJoinPool.defaultForkJoinWorkerThreadFactory,
         null, true);
}
public static ExecutorService newWorkStealingPool(int parallelism) {
    return new ForkJoinPool
        (parallelism,
         ForkJoinPool.defaultForkJoinWorkerThreadFactory,
         null, true);
}

newWorkStealingPool的实现借助于ForkJoinPool,关于ForkJoinPool的功能介绍将在后续文章中介绍。ForkJoinPool,Fork的意思的分支分叉,Join的意思的汇聚,ForkJoin就是先分叉再汇聚,比如在执行计算结果总和的过程中,对于不需要相互依赖不相关的几个计算过程,可以创建多个线程分别去执行某个计算过程,然后再统一将每个线程执行的结果汇聚(相加)起来。

  • unconfigurableExecutorService

将某个ExecutorService包装成另一个ExecutorService对象,这里的另一个对象就是DelegatedExecutorService。

public static ExecutorService unconfigurableExecutorService(ExecutorService executor) {
    if (executor == null)
        throw new NullPointerException();
    return new DelegatedExecutorService(executor);
}

在调用DelegatedExecutorService的相关方法时,实际还是调用的被包装的ExecutorService。如下面的代码所示,在调用DelegatedExecutorService的submit时候,实际是转发给e.submit方法。

public Future<?> submit(Runnable task) {
    return e.submit(task);
}

e就是被包装的ExecutorService,在DelegatedExecutorService的构造器中进行初始化。

private final ExecutorService e;
DelegatedExecutorService(ExecutorService executor) { e = executor; }
  • unconfigurableScheduledExecutorService

作用和unconfigurableExecutorService相同,只不过unconfigurableScheduledExecutorService包装的是具有定时执行任务功能的ScheduledExecutorService。

public static ScheduledExecutorService unconfigurableScheduledExecutorService(ScheduledExecutorService executor) {
    if (executor == null)
        throw new NullPointerException();
    return new DelegatedScheduledExecutorService(executor);
}

█ 其他方法

  • defaultThreadFactory
public static ThreadFactory defaultThreadFactory() {
    return new DefaultThreadFactory();
}

创建默认的线程工厂类,在创建ThreadPoolExecutor线程池中,如果没有指定线程工厂,就会使用这个默认的线程工厂。如下在ThreadPoolExecutor的构造器中通过调用Executors.defaultThreadFactory()来获取线程工厂。

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

DefaultThreadFactory:

static class DefaultThreadFactory implements ThreadFactory {
    private static final AtomicInteger poolNumber = new AtomicInteger(1);
    private final ThreadGroup group;
    private final AtomicInteger threadNumber = new AtomicInteger(1);
    private final String namePrefix;

    DefaultThreadFactory() {
        SecurityManager s = System.getSecurityManager();
        group = (s != null) ? s.getThreadGroup() :
                              Thread.currentThread().getThreadGroup();
        namePrefix = "pool-" +
                      poolNumber.getAndIncrement() +
                     "-thread-";
    }

    public Thread newThread(Runnable r) {
        Thread t = new Thread(group, r,
                              namePrefix + threadNumber.getAndIncrement(),
                              0);
        if (t.isDaemon())
            t.setDaemon(false);
        if (t.getPriority() != Thread.NORM_PRIORITY)
            t.setPriority(Thread.NORM_PRIORITY);
        return t;
    }
}
  • privilegedThreadFactory

获取带有权限控制功能的线程工厂。

public static ThreadFactory privilegedThreadFactory() {
    return new PrivilegedThreadFactory();
}

PrivilegedThreadFactory:

static class PrivilegedThreadFactory extends DefaultThreadFactory {
    private final AccessControlContext acc;
    private final ClassLoader ccl;

    PrivilegedThreadFactory() {
        super();
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            // Calls to getContextClassLoader from this class
            // never trigger a security check, but we check
            // whether our callers have this permission anyways.
            sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);

            // Fail fast
            sm.checkPermission(new RuntimePermission("setContextClassLoader"));
        }
        this.acc = AccessController.getContext();
        this.ccl = Thread.currentThread().getContextClassLoader();
    }

    public Thread newThread(final Runnable r) {
        return super.newThread(new Runnable() {
            public void run() {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        Thread.currentThread().setContextClassLoader(ccl);
                        r.run();
                        return null;
                    }
                }, acc);
            }
        });
    }
}
  • callable

提供了一个方法将Runnable转换成Callable类型。

public static <T> Callable<T> callable(Runnable task, T result) {
    if (task == null)
        throw new NullPointerException();
    return new RunnableAdapter<T>(task, result);
}

Runnable是不带有返回值结果的,而Callable是带有返回值结果的。所以可以通过第二个参数T result来指定,当Runnable类型的task执行完成之后,Callable的call方法返回的结果。

RunnableAdapter:

static final class RunnableAdapter<T> implements Callable<T> {
    final Runnable task;
    final T result;
    RunnableAdapter(Runnable task, T result) {
        this.task = task;
        this.result = result;
    }
    public T call() {
        task.run();
        return result;
    }
}

callable方法的重载:

public static Callable<Object> callable(Runnable task) {
    if (task == null)
        throw new NullPointerException();
    return new RunnableAdapter<Object>(task, null);
}

在此方法中,设置的T result参数为null,所以当Runnable task执行完成后,Callable的call方法返回值null。

  • privilegedCallable

增加了权限控制功能的转换。对参数传进来的Callable增加权限控制功能的调用。

public static <T> Callable<T> privilegedCallable(Callable<T> callable) {
    if (callable == null)
        throw new NullPointerException();
    return new PrivilegedCallable<T>(callable);
}

PrivilegedCallable:

static final class PrivilegedCallable<T> implements Callable<T> {
    private final Callable<T> task;
    private final AccessControlContext acc;

    PrivilegedCallable(Callable<T> task) {
        this.task = task;
        this.acc = AccessController.getContext();
    }

    public T call() throws Exception {
        try {
            return AccessController.doPrivileged(
                new PrivilegedExceptionAction<T>() {
                    public T run() throws Exception {
                        return task.call();
                    }
                }, acc);
        } catch (PrivilegedActionException e) {
            throw e.getException();
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值