线程池

162 阅读4分钟

构造参数的含义:

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) 

1. corePoolSize:核心线程数量。
默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中。
核心线程默认会一直存活在线程池中,即使核心线程处于闲置状态。
可以指定核心线程闲置时间超过KeepAliveTime,也可以进行销毁:allowCoreThreadTimeout=true
2. maximumPoolSize:线程池最大线程数
线程池中最多能创建的线程个数。
3. keepAliveTime:非核心线程闲置超时时间
当线程池的线程数大于corePoolSize时,并且多出来的部分闲置时间超过了keepAliveTime。那么这些线程将会被回收
4. TimeUnit:keepAliveTime的单位
MILLISECONDS : 1毫秒 、SECONDS : 秒、MINUTES : 分、HOURS : 小时、DAYS : 天
5. BlockingQueue:阻塞队列
一个阻塞队列,用于存储等待执行的任务。维护着等待执行的任务。若corePoolSize满了之后,则新添加的任务会被添加到这个队列中等待处理,如果队列满了,则创建非核心线程执行任务。
6. ThreadFactory:创建线程的方式
线程工厂,用于创建线程,一般使用默认的。
7. RejectedExecutionHandler:拒绝策略
当阻塞队列任务达到最大值并且已经开启的线程达到了最大线程数,若此时还有任务过来,就会执行拒绝策略。

拒绝策略

AbortPolicy丢弃任务并抛出RejectedExecutionException异常
DiscardPolicy丢弃任务,不抛出异常
DiscardOldestPolicy丢弃队列最前面的任务,然后重新尝试执行任务
CallerRunsPolicy只要线程池未关闭,该策略直接在调用者线程中串行运行被丢弃的任务,显然这样不会真的丢弃任务,但是可能会造成调用者性能急剧下降

线程池任务执行流程

  • 当线程池中线程数量小于corePoolSize,每来一个任务,就会创建一个线程执行这个任务。
  • 当前线程池线程数量大于等于corePoolSize,则每来一个任务。会尝试将其添加到任务缓存队列中,若是添加成功,则该任务会等待线程将其取出去执行;若添加失败(一般来说任务缓存队列已满),则会尝试创建新的线程执行。
  • 当前线程池线程数量等于maximumPoolSize,则会采取任务拒绝策略进行处理。
  • 当前线程池线程数量大于corePoolSize,如果某线程空闲时间超过keepAliveTime,线程将会被终止,直到不大于corePoolSize数量。如果允许为核心池(corePoolSize)中的线程设置存活时间,那么核心池中的线程空闲时间超过keepAliveTime,线程也会被终止。

任务缓存队列及排队策略

  • ArrayBlockingQueue:基于数组的先进先出队列,此队列创建必须指定大小;
  • LinkedBlockingQueue:基于链表的先进先出,默认大小无限大(注意内存溢出),吞吐量通常高于ArrayBlockingQueue。
  • synchronousQueue:不存储元素的存储队列,每个插入操作必须等待另一个线程调用移除操作,否则该插入操作一直处于阻塞状态。吞吐量要高于LinkedBlockingQueue。

线程池的关闭

ThreadPoolExecutor提供了两个方法,用于线程池的关闭。
shutdown():不会立即终止线程池,而是要等所有任务缓存队列中的任务都执行完后才终止,但再也不会接受新的任务
shutdownNow():立即终止线程池,并尝试打断正在执行的任务,并且清空任务缓存队列,返回尚未执行的任务

示例

创建一个最大线程数为3,阻塞队列大小为10的线程池。此时往线程池中提交20个任务,
则正常执行了13个任务,剩下的触发了拒绝策略,抛出异常。

public class ThreadPoolTest {

    private static ThreadPoolExecutor threadPoolExecutor;

    static {
        threadPoolExecutor =
                new ThreadPoolExecutor(1,
                        3,
                        5,
                        TimeUnit.MILLISECONDS,
                        new ArrayBlockingQueue(10),
                        Executors.defaultThreadFactory(),
                        new ThreadPoolExecutor.AbortPolicy());
    }

    public static void main(String[] args) throws InterruptedException {
        for (int i = 1; i <= 20; i++) {
            threadPoolExecutor.execute(new MyRunnable(i));
        }
        threadPoolExecutor.shutdown();
    }

    static class MyRunnable implements Runnable {
        private int i;

        public MyRunnable(int i) {
            this.i = i;
        }

        @Override
        public void run() {
            System.out.printf("第%d个任务执行成功%n",i);
        }
    }
}

image.png