Java - подробное объяснение пула потоков ThreadPoolExecutor

Java

руководство

Требовать: Ресурс потока должен пройти线程池При условии, что нельзя явно создавать потоки в самом приложении;инструкция: Преимущество использования пула потоков заключается в сокращении затрат времени на создание и уничтожение потоков и накладных расходов системных ресурсов, а также решении проблемы нехватки ресурсов. Если пул потоков не используется, это может привести к тому, что система создаст большое количество потоков одного типа, что может привести к потреблению памяти или "чрезмерному переключению".

«Руководство по Java для Alibaba»

Введение в пулы потоков

Обзор пула потоков

  Пул потоков, как следует из названия, представляет собой пул потоков, потоки этого пула в основном используются для выполнения задач. Когда пользователь отправляет задачу, пул потоков создает поток для выполнения задачи. Если задача превышает количество основных потоков, она помещается в очередь задач. Этот подробный процесс будет подробно рассмотрен позже.   Задача, обычно некоторые абстрактные и дискретные единицы работы, мы разобьем работу приложения на несколько задач для выполнения. Как правило, когда нам нужно использовать несколько потоков для выполнения задач, эти задачи предпочтительно независимы друг от друга, чтобы программа могла контролировать определенные границы задач.   Многопоточность, при использовании многопоточности процесс обработки задачи может быть отделен от основного потока, задачи могут обрабатываться параллельно, а несколько запросов могут обрабатываться одновременно. Конечно, код обработки задач должен быть потокобезопасным.

Зачем использовать пулы потоков?

  1. Уменьшить накладные расходы: при создании и уничтожении потоков будет много системных накладных расходов.Частое создание/удаление означает частое переключение и использование ресурсов ЦП.Потоки являются дефицитными ресурсами и не могут создаваться часто. Предполагая, что продолжительность создания потока записывается как t1, продолжительность выполнения потока записывается как t2, а продолжительность уничтожения потока записывается как t3, Если мы выполняем задачу t2
  2. Простое повторное использование и управление. Помещение всех потоков в пул удобно для унифицированного управления (отложенное выполнение, унифицированное имя потока и т. д.), и в то же время также легко повторно использовать задачи.
  3. Развязка: создание и уничтожение потоков полностью отделены от задач выполнения, что удобно для нас в обслуживании и позволяет больше сосредоточиться на развитии бизнеса.

Преимущества пулов потоков

  1. Улучшение использования ресурсов: Благодаря объединению в пул уже созданные потоки могут быть повторно использованы, а простаивающие потоки могут обрабатывать вновь отправленные задачи, тем самым уменьшая накладные расходы ресурсов на создание и уничтожение потоков.
  2. Улучшить управление потоками: управлять потоками, выполняющими задачи в пуле потоков, и может единообразно создавать, уничтожать и отслеживать потоки, контролировать количество потоков, предотвращать неограниченное создание потоков и избегать чрезмерного планирования ЦП из-за резкого увеличения количества потоков. и т. д., чтобы более разумно распределять и использовать ресурсы ядра.
  3. Улучшить отзывчивость программы: после отправки задачи существует бездействующий поток, который может выполнить задачу напрямую, не создавая новую.
  4. Улучшить масштабируемость системы: Использование пула потоков может лучше расширить некоторые функции, например, пул потоков синхронизации может реализовать задачи синхронизации системы.

Принцип пула потоков

Тип параметра пула потоков

Всего их 7: corePoolSize, maxPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler, (5+2, первые 5 важны)

int corePoolSize: максимальное количество основных потоков в пуле потоков

Здесь мы различаем два понятия:

  • основная нить: Когда новый поток создается в пуле потоков,当前活动的线程总数< corePoolSize, вновь созданный поток является основным потоком.
  • неосновная нить: Когда новый поток создается в пуле потоков,当前活动的线程总数> corePoolSize, и очередь блокировки заполнена, то создается новый поток для выполнения только что отправленной задачи, которая является неосновным потоком.

Основной поток всегда будет жить в пуле потоков по умолчанию, даже если основной поток не работает (состояние простоя), если толькоThreadPoolExecutor 的 allowCoreThreadTimeOutЭто свойствоtrue, то если основной поток простаивает, он будет уничтожен через определенный промежуток времени.

int maxPoolSize: максимальное количество потоков

Всего потоков = основные потоки + неосновные потоки

long keepAliveTime: тайм-аут простоя неосновного потока

  keepAliveTime — это максимальное время выживания, разрешенное простаивающим потокам. Если неосновной поток простаивает дольше, чем keepAliveTime, он будет уничтожен. Примечание: если установленоallowCoreThreadTimeOut = true, он становится основным потоком с истекшим временем ожидания и уничтоженным.

Единица TimeUnit: единица измерения keepAliveTime.

TimeUnit — это тип перечисления, указанный ниже:

единица измерения инструкция
NANOSECONDS 1 микросекунда = 1 микросекунда / 1000
MICROSECONDS 1 микросекунда = 1 миллисекунда / 1000
MILLISECONDS 1 миллисекунда = 1 секунда / 1000
SECONDS второй
MINUTES Минута
HOURS Час
DAYS небо

BlockingQueue workQueue: блокирующая очередь для хранения задач.

  Когда все основные потоки работают, новые отправленные задачи будут добавлены в очередь блокировки работы для постановки в очередь; если очередь блокировки также заполнена, пул потоков создаст новый неосновной поток для выполнения задачи. WorkQueue поддерживает объекты Runnable, ожидающие выполнения.Общие типы рабочих очередей:(неограниченная очередь, ограниченная очередь, очередь синхронного хендовера)

  1. SynchronousQueue: очередь синхронного хендовера,适用于非常大的或者无界的线程池,可以避免任务排队, после того как очередь SynchronousQueue получит задачу, она直接将任务从生产者移交给工作者线程, этот механизм передачи эффективен. Это очередь, которая не хранит элементы.Задача не будет помещаться в очередь, чтобы ждать, пока поток ее извлечет, а будет непосредственно передана исполняющему потоку. Использование очереди SynchronousQueue имеет смысл только в том случае, если пул потоков неограничен или может отклонять задачи.MaximumPoolSize обычно указывается как Integer.MAX_VALUE, что является бесконечным. Чтобы поместить элемент в SynchronousQueue, должен существовать другой поток, ожидающий получения элемента. Если нет ожидающих потоков и текущее количество потоков в пуле потоков меньше максимального значения, ThreadPoolExecutor создаст новый поток; в противном случае задача будет отклонена в соответствии с политикой насыщения.newCachedThreadPoolЭта очередь синхронной передачи используется по умолчанию. Пропускная способность выше, чем у LinkedBlockingQueue.
  2. LinkedBlockingQueue: на основе链表结构блокирующая очередь,FIFO原则排序. При отправке задачи, если текущее количество потоков меньше количества основных потоков corePoolSize, пул потоков создает новый основной поток для выполнения задачи; если текущее количество потоков равно количеству основных потоков corePoolSize , он переходит в рабочую очередь для ожидания. Для очереди LinkedBlockingQueue нет максимального ограничения, пока количество задач превышает количество основных потоков, они будут добавлены в очередь, что приведет к总线程数永远不会超过 corePoolSize, поэтому maxPoolSize является недопустимым параметром.newFixedThreadPoolиnewSingleThreadPoolПо умолчанию используется无界LinkedBlockingQueue队列. Пропускная способность выше, чем у ArrayBlockingQueue.
  3. ArrayBlockingQueue: на основе数组结构из有界Блокировка очереди, вы можете установить верхний предел очереди,FIFO原则排序. При отправке задачи, если текущий поток меньше, чем количество основных потоков corePoolSize, будет создан новый основной поток для выполнения задачи; если количество текущих потоков равно количеству основных потоков corePoolSize, будет создан новый основной поток. войти в очередь на ожидание, если количество задач в очереди также заполнено, создать новый неосновной поток, основной поток выполняет задание, если очередь заполнена и общее количество потоков достигает maxPoolSize максимальное количество потоков задача отклоняется в соответствии с политикой насыщения.
  4. DelayQueue: очередь с задержкой, элементы в очереди должны реализовывать интерфейс с задержкой. Когда задача отправлена, задача будет выполнена только после достижения указанного времени задержки после постановки в очередь.
  5. PriorityBlockingQueue: Очередь блокировки приоритета, выполнение задач в соответствии с приоритетом, приоритет реализуется путем естественной сортировки или определения компаратора.

Уведомление:Только когда задачи независимы друг от друга без каких-либо зависимостей, разумно задать ограниченный пул потоков или рабочую очередь; если между задачами есть зависимости, нужно использовать неограниченный пул потоков, например newCachedThreadPool, иначе это может привести к заблокировать проблемы.

ThreadFactory threadFactory

  Способ создания потока, это интерфейс, вам нужно реализовать его метод Thread newThread(Runnable r) при его создании, который обычно не используется.

Обработчик RejectedExecutionHandler: стратегия насыщения

Генерация исключений предназначена для политики насыщения, когда и очередь, и максимальный пул потоков заполнены.

Рабочий процесс пула потоков

Общий процесс таков: создание рабочих потоков; добавление задач в очередь workQueue; рабочие потоки выполняют задачи.

在这里插入图片描述
Когда задача добавляется в пул потоков:

  1. Текущее количество потоков未达到 corePoolSize,но新建一个线程(核心线程)выполнять задачи
  2. Текущее количество потоков达到了 corePoolSize, переместите задачу в阻塞队列等待, пусть процесс бездействующего потока;
  3. когда заблокирован队列已满,新建线程(非核心线程)выполнять задачи
  4. Когда очередь блокировки заполнена,总线程数又达到了 maximumPoolSize, задачи, которые не могут быть выполнены, будут обрабатываться в соответствии с политикой отклонения, например, RejectedExecutionHandler выдает исключение.

Вот, чтобы всем было лучше понятно этот процесс, разберем на примере. В жизни мы часто делаем запросы от компаний или жалобы от конкретных организаций, и центр обслуживания клиентов этой компании или организации является线程池, дама обслуживания клиентов постоянного работника, как核心线程, Например, есть 6 дам обслуживания клиентов. 5. Когда пользователь звонит по телефону в центр обслуживания клиентов компании.(提交任务); 6. 客服中心会调度客服小姐姐去接听电话(创建线程执行任务), если получено более 6 звонков, все 6 дам и сестер службы поддержки находятся в рабочем состоянии и отвечают(核心线程池满了), то будет канал ожидания вызова в центре обслуживания клиентов(进入任务队列等待), что мы часто слышим: «Ваш звонок в очереди, и в очереди n человек». 7. Разумеется, есть и верхний предел канала ожидания для этого звонка, при превышении верхнего предела(任务队列满了), центр обслуживания клиентов немедленно организует внешний персонал(非核心线程), то есть неофициальные сотрудники для ответа на дополнительные звонки(任务队列满了,正式和非正式员工数量>总任务数,线程池创建非核心线程去执行任务). 8. Когда количество пользовательских звонков резко возросло, консоль центра обслуживания клиентов обнаружила, что сумма штатных и сторонних сотрудников больше не может удовлетворить телефонный доступ этих пользователей.(总线程池满), начали отклонять эти звонки в соответствии с некоторыми правилами ответа на телефонные звонки компании.(按照拒绝策略处理无法执行的任务)

состояние пула потоков

在这里插入图片描述

  • RUNNING: Состояние выполнения, что означает, что задачи могут быть приняты, а задачи в очереди могут быть выполнены.
  • SHUTDOWN: вызывается метод shutdown(), и новые задачи не принимаются, но задачи в очереди будут выполняться.
  • STOP: означает, что вызывается метод shutdownNow(), новые задачи не принимаются, и все задачи становятся STOP, независимо от того, выполняются они или нет. Эта операция отбрасывает все задачи в очереди блокировки и прерывает выполнение всех задач.
  • TIDYING: после выполнения всех задач программа вызывает метод shutdown()/shutdownNow(), чтобы обновить поток до этого состояния.Если вызывается shutdown(), очередь будет пустой и перейдет в состояние TIDYING, когда все задачи будут выполнены. shutdownNow После метода () задача в очереди очищается, выполнение задачи прерывается, а состояние обновляется до TIDYING.
  • TERMINATED: Завершенное состояние, когда поток выполняетсяterminated()Позже он будет обновлен до этого статуса.

Исходный код пула потоков

основной интерфейс пула потоков

ThreadPoolExecutor, в java.util.concurrent.

    /**
     * Creates a new {@code ThreadPoolExecutor} with the given initial
     * parameters.
     *
     * @param corePoolSize the number of threads to keep in the pool, even
     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
     * @param maximumPoolSize the maximum number of threads to allow in the
     *        pool
     * @param keepAliveTime when the number of threads is greater than
     *        the core, this is the maximum time that excess idle threads
     *        will wait for new tasks before terminating.
     * @param unit the time unit for the {@code keepAliveTime} argument
     * @param workQueue the queue to use for holding tasks before they are
     *        executed.  This queue will hold only the {@code Runnable}
     *        tasks submitted by the {@code execute} method.
     * @param threadFactory the factory to use when the executor
     *        creates a new thread
     * @param handler the handler to use when execution is blocked
     *        because the thread bounds and queue capacities are reached
     * @throws IllegalArgumentException if one of the following holds:<br>
     *         {@code corePoolSize < 0}<br>
     *         {@code keepAliveTime < 0}<br>
     *         {@code maximumPoolSize <= 0}<br>
     *         {@code maximumPoolSize < corePoolSize}
     * @throws NullPointerException if {@code workQueue}
     *         or {@code threadFactory} or {@code handler} is null
     */
    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;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

ThreadPoolExecutor наследует AbstractExecutorService, AbstractExecutorService реализует ExecutorService, а ExecutorService наследует Executor.

在这里插入图片描述

public class ThreadPoolExecutor extends AbstractExecutorService {}
public abstract class AbstractExecutorService implements ExecutorService {}
public interface ExecutorService extends Executor {}

Конструктор пула потоков

1) 5-параметрический конструктор

// 5参数构造器
public ThreadPoolExecutor(int corePoolSize,
		             	int maximumPoolSize,
			long keepAliveTime,
			TimeUnit unit,
			BlockingQueue<Runnable> workQueue)

2) 6-параметрический конструктор-1

// 6参数构造器-1
public ThreadPoolExecutor(int corePoolSize,
		             	int maximumPoolSize,
			long keepAliveTime,
			TimeUnit unit,
			BlockingQueue<Runnable> workQueue,
			ThreadFactory threadFactory)

3) 6-параметрический конструктор-2

// 6参数构造器-2
public ThreadPoolExecutor(int corePoolSize,
		             	int maximumPoolSize,
			long keepAliveTime,
			TimeUnit unit,
			BlockingQueue<Runnable> workQueue,
			RejectedExecutionHandler handler)

4) конструктор с 7 параметрами

// 7参数构造器
public ThreadPoolExecutor(int corePoolSize,
		             	int maximumPoolSize,
			long keepAliveTime,
			TimeUnit unit,
			BlockingQueue<Runnable> workQueue,
			ThreadFactory threadFactory,
			RejectedExecutionHandler handler)

Четыре пула потоков

нормальное использование

//创建固定数目线程的线程池
Executors.newFixedThreadPool(200);

//创建一个无限线程的线程池,无需等待队列,任务提交即执行
Executors.newCachedThreadPool()

//创建有且仅有一个线程的线程池
Executors.newSingleThreadExecutor();

newCachedThreadPool(): кешируемый пул потоков

вводить

newCachedThreadPool создаст кешируемый поток. Если текущее количество потоков превышает количество задач обработки, простаивающие потоки будут переработаны, а когда потребность возрастет, новые потоки могут быть добавлены к задачам обработки.

  1. Количество потоков не ограничено, значение corePoolSize равно 0, а значение maxPoolSize равно Integer.MAX_VALUE.
  2. Если поток не перезапущен, при поступлении задачи будет повторно использован бездействующий поток; если бездействующий поток отсутствует, для выполнения задачи будет создан новый поток.
  3. Благодаря возможности повторного использования некоторые программы сокращают частоту создания/удаления потоков и снижают нагрузку на систему.
  4. Рабочая очередь может выбрать SynchronousQueue.
Создать метод

ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

исходный код
    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

newFixedThreadPool(): пул потоков фиксированной длины

вводить

newFixedThreadPool создает пул потоков фиксированной длины, и каждый раз при отправке задачи создается новый поток, пока не будет достигнуто максимальное количество пулов потоков.

  1. Фиксированная длина, вы можете контролировать максимальное количество одновременных потоков.Значения corePoolSize и maxPoolSize оба являются nThreads.
  2. Превышенные потоки будут ждать в очереди.
  3. Рабочая очередь может выбрать LinkedBlockingQueue.
Создать метод

ExecutorService fixedThreadPool = Executors.newFixedThreadPool(int nThreads);

исходный код
    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

newScheduledThreadPool(): пул потоков по времени

вводить

newScheduledThreadPool создает пул потоков фиксированной длины и выполняет задачи с задержкой или по времени.

Создать метод:

ExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(int corePoolSize);

исходный код
    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }

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

newSingleThreadExecutor(): однопоточный пул потоков

вводить

Как следует из названия, newSingleThreadExecutor — это однопоточный Executor, который создает только один рабочий поток для выполнения задач. Если единственный поток выходит из строя, для его замены создается другой поток. newSingleThreadExecutor может гарантировать, что задачи выполняются последовательно в соответствии с очередью порядок в очереди на работу. .

  1. Существует один и только один рабочий поток для выполнения задачи;
  2. Все задачи выполняются в порядке очереди рабочей очереди, сначала в порядке поступления.
  3. Пул потоков одиночного потока заключается в том, что за задачу отвечает только один поток в пуле потоков, поэтому значения corePoolSize и maxPoolSize оба равны 1; при возникновении любого исключения в этом потоке пул потоков автоматически создаст thread и всегда держите пул потоков и только живой поток.
  4. Рабочая очередь может выбрать LinkedBlockingQueue.
Создать метод

ExecutorService singleThreadPool = Executors.newSingleThreadPool();

исходный код
    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

    static class FinalizableDelegatedExecutorService
        extends DelegatedExecutorService {
        FinalizableDelegatedExecutorService(ExecutorService executor) {
            super(executor);
        }
        protected void finalize() {
            super.shutdown();
        }
    }

метод выполнения()

вводить

Метод ThreadPoolExecutor.execute(Runnable command), вы можете добавить задачу в пул потоков

выполнить исходный код
    /**
     * Executes the given task sometime in the future.  The task
     * may execute in a new thread or in an existing pooled thread.
     *
     * If the task cannot be submitted for execution, either because this
     * executor has been shutdown or because its capacity has been reached,
     * the task is handled by the current {@code RejectedExecutionHandler}.
     *
     * @param command the task to execute
     * @throws RejectedExecutionException at discretion of
     *         {@code RejectedExecutionHandler}, if the task
     *         cannot be accepted for execution
     * @throws NullPointerException if {@code command} is null
     */
    public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        /*
         * Proceed in 3 steps:
         *
         * 1. If fewer than corePoolSize threads are running, try to
         * start a new thread with the given command as its first
         * task.  The call to addWorker atomically checks runState and
         * workerCount, and so prevents false alarms that would add
         * threads when it shouldn't, by returning false.
         *
         * 2. If a task can be successfully queued, then we still need
         * to double-check whether we should have added a thread
         * (because existing ones died since last checking) or that
         * the pool shut down since entry into this method. So we
         * recheck state and if necessary roll back the enqueuing if
         * stopped, or start a new thread if there are none.
         *
         * 3. If we cannot queue task, then we try to add a new
         * thread.  If it fails, we know we are shut down or saturated
         * and so reject the task.
         */
	//获取当前线程池的状态
        int c = ctl.get();
	//若当前线程数量小于corePoolSize,则创建一个新的线程
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
	//判断当前线程是否处于运行状态,且写入任务阻塞队列是否成功
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
	//再次获取线程状态进行双重检查;如果线程变成非运行状态,则从阻塞队列移除任务;
            if (! isRunning(recheck) && remove(command))
	//执行拒绝策略
                reject(command);
	//若当前线程池为空,则新建一个线程
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
	//当前线程为非运行状态并且尝试新建线程,若失败则执行拒绝策略。
        else if (!addWorker(command, false))
            reject(command);
    }
Анализ процесса

1) Если当前线程数小于corePoolSize, затем вызовите метод addWorker(), чтобы создать поток для выполнения задачи. 2) Если当前线程不小于corePoolSize, задача добавляется в очередь workQueue, ожидая выполнения бездействующего потока. 3) Если队列里的任务数到达上限当前运行线程小于maximumPoolSize, задача не может войти в очередь workQueue, и ее выполняет новый поток; 4) Если создание потока также не удается (队列任务数到达上限当前线程数达到了maximumPoolSize), для вновь добавленной задачи будет вызываться reject() (внутренний обработчик вызовов), чтобы отказаться принять задачу.

Q&A

Разница между двумя типами закрытия пулов потоков

  • shutdown(): прекратите принимать новые задачи после выполнения, и задачи в очереди будут выполнены.
  • shutdownNow(): перестанет принимать новые задачи после выполнения, но прервет все задачи (независимо от того, выполняются они или нет) и изменит состояние пула потоков на состояние STOP.

Какова политика отказа?

Стратегия насыщения ThreadPoolExecutor может быть достигнута путем вызоваsetRejectedExecutionHandlerмодифицировать. JDK предоставляет несколько различных реализаций RejectedExecutionHandler, каждая из которых имеет свою политику насыщения: AbortPolicy, CallerRunsPolicy, DiscardPolicy и DiscardOldestPolicy. Политика отказа заключается в следующем:

  • CallerRunsPolicy : вызывающий поток обрабатывает задачу
  • AbortPolicy : создать исключение
  • DiscardPolicy : Отменить напрямую
  • DiscardOldestPolicy: отбросить самую старую задачу в очереди и выполнить новую задачу.

RejectedExecutionHandler rejected = null;

//默认策略,阻塞队列满,则丢任务、抛出异常
rejected = new ThreadPoolExecutor.AbortPolicy();

//阻塞队列满,则丢任务,不抛异常
rejected = new ThreadPoolExecutor.DiscardPolicy();

//删除队列中最旧的任务(最早进入队列的任务),尝试重新提交新的任务
rejected = new ThreadPoolExecutor.DiscardOldestPolicy();

//队列满,不丢任务,不抛异常,若添加到线程池失败,那么主线程会自己去执行该任务
rejected = new ThreadPoolExecutor.CallerRunsPolicy();

(1) AbortPolicy, DiscardPolicy и DiscardOldestPolicy  AbortPolicyда默认的饱和策略, заключается в том, чтобы прервать задачу, стратегия выдаст исключение RejectedExecutionException. Вызывающий может перехватить это исключение, а затем написать код для обработки исключения.    Когда новая отправленная задача无法保存到队列В ожидании исполнения вDiscardPolicyбудет молчать抛弃该任务.   DiscardOldestPolicyбудет抛弃最旧的(следующая задача для выполнения), затем попробуйте повторно отправить новую задачу. Если рабочая очередь является очередью с приоритетом, политика насыщения DiscardOldestPolicy приведет к отбрасыванию задачи с наивысшим приоритетом, поэтому не используйте их вместе.(2) CallerRunsPolicy  CallerRunsPolicy — это политика «запуска вызывающего абонента», которая реализует механизм модерации. Это不会抛弃任务,также不会抛出异常. но将任务回退到调用者. Это不会在线程池中выполнить задание, но在一个调用了execute的线程中выполнить это задание. После заполнения потока новая задача будет выполняться основным потоком, который вызывает метод execute пула потоков, а поскольку основной поток занят, метод accept не будет выполняться, что приведет к незначительному снижению производительности.    Когда рабочая очередь заполнена, нет предопределенной политики насыщения для блокировки выполнения (за исключением того, что отбрасывание означает прерывание и разрешение выполнения вызывающей стороне). Однако скорость поступления задач может быть ограничена семафором.

Ссылаться на «Практика параллельного программирования на Java» исходный пакет jdk 1.8