线程池源码解析——原理概述

corePoolSize核心线程

线程池的基本大小,即在没有任务需要执行的时候线程的大小,并且只有在工作队列满了的情况下才会创建出超出这个数量的线程。

核心线程是否会被回收?

  1. 核心线程将一直保存在线程池中。
  2. 哪怕核心线程是处于空闲状态,也可以不回收。
  3. allowCoreThreadTimeOut参数可以控制是否回收核心线程。
  4. 在刚刚创建线程池的时候,核心线程并不会立刻启动,而是要等到有任务提交时才会启动。
  5. prestartCoreThread/prestartAllCoreThread方法可以事先启动核心线程。

阻塞队列

当所有的核心线程处于工作状态时,再向线程池提交任务,将无核心线程可以直接处理。阻塞队列就是保存这些将要被线程池执行的任务的。

阻塞队列注意事项

  1. BlockingQueue接口的所有子类都可以作为阻塞队列。
  2. 阻塞队列的容量问题要注意。如果选择无界阻塞队列,即线程池的核心线程都处于工作状态后,线程池将无限制的接收所有的任务,可能会造成阻塞队列过长,影响JVM性能,严重情况下可能会造成OOM。

maximumPoolSize最大线程数

线程池中允许的最大线程数,线程池中所有的线程数目不会超过该值。如果线程池队列中任务已满,并且当前线程个数小于maximumPoolSize,那么会创建新的线程来执行任务。这部分创建出的线程叫做非核心线程。

另外largestPoolSize,该变量记录了线程池在整个生命周期中曾经出现的最大线程个数。之所以是曾经,是因为线程城池创建之后,可以调用setmaximumPoolSize()改变运行的最大线程的数目。

非核心线程是否会被回收?

  1. 非核心线程是会被回收的。
  2. keepAliveTimeOut/unit控制非核心线程最大的空闲时间,超过这个时间还没有任务可以执行,非核心线程将会被回收。

线程工厂

线程工厂就是线程池创建线程的工厂,ThreadPoolExecutor使用了Executors提供的默认线程工厂,代码如下:

    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;
        }
    }

如果有需求或者必要,可以定义自己的线程工厂,只要实现ThreadFactory接口即可,如:

    static class NameThreadFactory implements ThreadFactory{
        //线程ID
        private final AtomicInteger threadId = new AtomicInteger(1);
        @Override
        public Thread newThread(Runnable r) {
            Thread t = new Thread(r,"线程-" + threadId.getAndIncrement());
            System.out.println(t.getName() + " 已经被创建");
            return t;
        }
    }

拒绝策略/饱和策略

当线程池的线程数达到最大,并且阻塞队列的容量也达到了最大的时候,线程池将达到最大负载,此时如果再向线程池中添加任务,线程池将无法继续处理。线程池的拒绝策略就是为了保护线程池的负载。

ThreadPoolExecutor提供了四种拒绝策略:
在这里插入图片描述
你也可以通过实现RejectedExecutionHandler来定义自己的拒绝策略。

CallerRunsPolicy

由线程池的调用线程(调用execute方法的线程)执行任务,线程池本身处于饱和状态时不再受理任何外部提交的任务。

    public static class CallerRunsPolicy implements RejectedExecutionHandler {
        /**
         * Creates a {@code CallerRunsPolicy}.
         */
        public CallerRunsPolicy() { }

        /**
         * Executes task r in the caller's thread, unless the executor
         * has been shut down, in which case the task is discarded.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                r.run();
            }
        }
    }

AbortPolicy

通过抛出RejectedExecutionException异常的方式拒绝执行任务。

    public static class AbortPolicy implements RejectedExecutionHandler {
        /**
         * Creates an {@code AbortPolicy}.
         */
        public AbortPolicy() { }

        /**
         * Always throws RejectedExecutionException.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         * @throws RejectedExecutionException always
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            throw new RejectedExecutionException("Task " + r.toString() +
                                                 " rejected from " +
                                                 e.toString());
        }
    }

DiscardPolicy

悄悄把任务丢弃,不做任何处理和记录。

    public static class DiscardPolicy implements RejectedExecutionHandler {
        /**
         * Creates a {@code DiscardPolicy}.
         */
        public DiscardPolicy() { }

        /**
         * Does nothing, which has the effect of discarding task r.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        }
    }

DiscardOldestPolicy

丢弃队列中最早进入队列的任务,然后再次尝试执行这次提交给线程池的任务。

    public static class DiscardOldestPolicy implements RejectedExecutionHandler {
        /**
         * Creates a {@code DiscardOldestPolicy} for the given executor.
         */
        public DiscardOldestPolicy() { }

        /**
         * Obtains and ignores the next task that the executor
         * would otherwise execute, if one is immediately available,
         * and then retries execution of task r, unless the executor
         * is shut down, in which case task r is instead discarded.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                e.getQueue().poll();
                e.execute(r);
            }
        }
    }

自定义拒绝策略

    public static class MyIgnorePolicy implements RejectedExecutionHandler{
        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
            doLog(r,executor);
        }
        private void doLog(Runnable r, ThreadPoolExecutor executor){
            System.err.println(r.toString() + " rejiected");
        }
    }

线程池执行原理图

概略图

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值