自定义线程池的构建原理

x33g5p2x  于2022-05-11 转载在 其他  
字(2.9k)|赞(0)|评价(0)|浏览(283)

一 点睛

如果已有的线程池都不能满足业务的需求,那么就可以通过 ThreadPoolExecutor 来自定义一种类型的线程池。具体地说,可以通过 ThreadPoolExecutor 的构造方法来创建一个自定义的线程池对象,并且通过 execute 向池中提交无返回值的任务(类似于 run() 方法),或者使用 submit() 向池中提交有返回值的任务(同样是用 Future 接收返回值)。

二 源码分析

public class ThreadPoolExecutor extends AbstractExecutorService {
    // 根据不同的参数个数,一共有4种用于创建 ThreadPoolExecutor 对象的构造方法
    public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
         Executors.defaultThreadFactory(), defaultHandler);
    }
    public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
         threadFactory, defaultHandler);
    }
    public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          RejectedExecutionHandler handler) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
         Executors.defaultThreadFactory(), handler);
    }
    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.acc = System.getSecurityManager() == null ?
            null :
            AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        his.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }
}

三 构造方法参数说明

1 corePoolSize

线程池中核心线程数的最大值。核心线程是指一旦有任务提交,核心线程就会去执行。

2 maximumPoolSize

线程池中最多能容纳的线程总数。线程总数 = 核心线程数 + 非核心线程数。非核心线程是指如果有任务提交,任务先交给核心线程去执行,如果核心线程满了再将任务放到 workQueue 中,如果 workQueue 也满了才将任务交给非核心线程去只执行。

3 keepAliveTime

线程中非核心线程的最大空闲时长。如果超过了该时间,空闲的非核心线程就会从线程池中被删除。如果设置了 allowCoreThreadTimeOut = true,那么 keepAliveTime 也会作用于核心线程。

4 unit

keepAliveTime 的时间单位。

5 workQueue

等待提交到线程池中的任务队列。如果所有核心线程都在执行,那么新添加的任务就会被增加到这个队列等待处理;如果队列满了,线程池就会创建非核心线程去执行这些无法添加到队列中的任务;如果向线程池中提交的任务数量 > (maximumPoolSize+workQueue.size())时,程序就会抛出异常,异常类型取决于构造方法的最后一个参数 handler。

6 threadFactory

创建线程的方式。一般不用设置,使用默认值即可。

7 handler

拒绝策略。当向线程池中提交的任务已满,即向线程池中提交的任务数量 > (maximumPoolSize+workQueue.size())时,如何拒绝超额的任务。拒绝策略的上级接口是 RejectedExecutionHandler,该接口定义了拒绝时执行的方法 rejectedExecution,源码如下。

public interface RejectedExecutionHandler {
    void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}

该接口的4个实现类,就是4种拒绝策略。

AbortPolicy:默认拒绝策略,如果 maximumPoolSize+workQueue.size() 已经饱和,就丢掉超额的任务,并抛出 RejectedExecutionHandler 异常。

DiscardPolicy:如果 maximumPoolSize+workQueue.size() 已经饱和,就丢掉超额的任务,但不会抛出异常。

DiscardOldestPolicy:队列是 FIFO 的结构,当采用此策略时,如果已经饱和就删除最早进入队列的任务,再将新任务追加到队尾。

CallerRunsPolicy:如果饱和,新任务不会去尝试添加到 workQueue 中,而是直接去调用 execute(),是一种"急脾气"的策略。

此外,还可以自定义一个实现 RejectedExecutionHandler 接口的类,即自定义拒绝策略。

相关文章