Обзор параллелизма Java с Zhu Ye (1): пул потоков

Java

Как и в моих предыдущих статьях из серии Spring, мы рассмотрим некоторые моменты знаний, проведя несколько демонстрационных экспериментов. В этой статье мы начнем с наиболее часто используемых пулов потоков в параллелизме Java.

Начните с эксперимента с пулом потоков

Во-первых, мы пишем метод для периодического вывода основной информации о пуле потоков один раз в секунду:

private void printStats(ThreadPoolExecutor threadPool){
    Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> {
        log.info("=========================");
        log.info("Pool Size: {}", threadPool.getPoolSize());
        log.info("Active Threads: {}", threadPool.getActiveCount());
        log.info("Number of Tasks Completed: {}", threadPool.getCompletedTaskCount());
        log.info("Number of Tasks in Queue: {}", threadPool.getQueue().size());

        log.info("=========================");
    }, 0, 1, TimeUnit.SECONDS);
}

Затем мы пишем метод для регулярной отправки задач в пул потоков:

private void submitTasks(AtomicInteger atomicInteger, ThreadPoolExecutor threadPool) {
    IntStream.rangeClosed(1, 20).forEach(i -> {
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        int id = atomicInteger.incrementAndGet();
        threadPool.submit(() -> {
            log.info("{} started", id);
            try {
                TimeUnit.SECONDS.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("{} finished", id);
        });
    });
}

можно увидеть:

  • Всего 20 заданий
  • Отправляйте задачу каждую секунду
  • Каждая задача выполняется 10 секунд
  • Содержание задания очень простое, то есть счетчик накапливается

Теперь пишем самый распространенный пул потоков и ждем завершения всех задач в пуле потоков:

@Test
public void test1() throws InterruptedException {
    AtomicInteger atomicInteger = new AtomicInteger();
    ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
            2, 5,
            5, TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(10));

    printStats(threadPool);
    submitTasks(atomicInteger,threadPool);
    threadPool.shutdown();
    threadPool.awaitTermination(1, TimeUnit.HOURS);
}

Как видите, этот пул потоков:

  • 2 основных потока
  • 5 макс. потоков
  • 5-секундный предел повторного использования (макс.) потоков
  • Очередь до 10 задач

Для такой конфигурации подумайте о том, как работает пул потоков после отправки задачи. Набралось несколько вопросов:

  • Сколько потоков будет в пуле потоков в начале?
  • Сколько потоков будет медленно увеличиваться в пуле потоков?
  • Можно ли выполнить эти задачи?

Давайте посмотрим на вывод после выполнения:

09:51:37.709 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:37.715 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 0
09:51:37.718 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 0
09:51:37.718 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 0
09:51:37.718 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in queue: 0
09:51:37.718 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:38.705 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:38.705 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 0
09:51:38.705 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 0
09:51:38.705 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 0
09:51:38.705 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in queue: 0
09:51:38.705 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:38.716 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 1 started
09:51:39.701 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:39.701 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 1
09:51:39.702 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 1
09:51:39.702 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 0
09:51:39.702 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in queue: 0
09:51:39.702 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:39.718 [pool-1-thread-2] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 2 started
09:51:40.704 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:40.704 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 2
09:51:40.704 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 2
09:51:40.704 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 0
09:51:40.704 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in queue: 0
09:51:40.704 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:41.701 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:41.701 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 2
09:51:41.702 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 2
09:51:41.702 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 0
09:51:41.702 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in queue: 1
09:51:41.702 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:42.702 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:42.702 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 2
09:51:42.702 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 2
09:51:42.702 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 0
09:51:42.702 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in queue: 2
09:51:42.702 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:43.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:43.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 2
09:51:43.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 2
09:51:43.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 0
09:51:43.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in queue: 3
09:51:43.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:44.701 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:44.701 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 2
09:51:44.701 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 2
09:51:44.702 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 0
09:51:44.702 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in queue: 4
09:51:44.702 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:45.702 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:45.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 2
09:51:45.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 2
09:51:45.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 0
09:51:45.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in queue: 5
09:51:45.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:46.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:46.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 2
09:51:46.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 2
09:51:46.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 0
09:51:46.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in queue: 6
09:51:46.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:47.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:47.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 2
09:51:47.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 2
09:51:47.704 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 0
09:51:47.704 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in queue: 7
09:51:47.704 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:48.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:48.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 2
09:51:48.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 2
09:51:48.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 0
09:51:48.704 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in queue: 8
09:51:48.704 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:48.719 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 1 finished
09:51:48.719 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 3 started
09:51:49.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:49.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 2
09:51:49.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 2
09:51:49.704 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 1
09:51:49.704 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in queue: 8
09:51:49.704 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:49.720 [pool-1-thread-2] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 2 finished
09:51:49.720 [pool-1-thread-2] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 4 started
09:51:50.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:50.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 2
09:51:50.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 2
09:51:50.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 2
09:51:50.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in queue: 8
09:51:50.704 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:51.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:51.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 2
09:51:51.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 2
09:51:51.704 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 2
09:51:51.704 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in queue: 9
09:51:51.704 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:52.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:52.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 2
09:51:52.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 2
09:51:52.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 2
09:51:52.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in queue: 10
09:51:52.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:52.749 [pool-1-thread-3] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 15 started
09:51:53.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:53.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 3
09:51:53.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 3
09:51:53.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 2
09:51:53.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in queue: 10
09:51:53.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:53.754 [pool-1-thread-4] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 16 started
09:51:54.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:54.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 4
09:51:54.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 4
09:51:54.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 2
09:51:54.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in queue: 10
09:51:54.704 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:54.755 [pool-1-thread-5] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 17 started
09:51:55.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
09:51:55.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
09:51:55.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
09:51:55.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 2
09:51:55.703 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in queue: 10
09:51:55.704 [pool-2-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================

java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@fdefd3f[Not completed, task = java.util.concurrent.Executors$RunnableAdapter@1a0dcaa[Wrapped task = me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest$$Lambda$50/0x0000000800105840@3bd40a57]] rejected from java.util.concurrent.ThreadPoolExecutor@d83da2e[Running, pool size = 5, active threads = 5, queued tasks = 10, completed tasks = 2]

	at java.base/java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2055)
	at java.base/java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:825)
	at java.base/java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1355)
	at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:118)
	at me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest.lambda$submitTasks$2(ThreadPoolExecutorTest.java:33)
	at java.base/java.util.stream.Streams$RangeIntSpliterator.forEachRemaining(Streams.java:104)
	at java.base/java.util.stream.IntPipeline$Head.forEach(IntPipeline.java:593)
	at me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest.submitTasks(ThreadPoolExecutorTest.java:26)
	at me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest.test1(ThreadPoolExecutorTest.java:54)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

Вы можете увидеть из вывода:

  • Хотя настроено 2 основных потока, в начале пул потоков по-прежнему равен 0. Вы можете изменить это поведение с помощью threadPool.prestartAllCoreThreads(), чтобы инициализировать все основные потоки.
  • По мере отправки задач основные потоки медленно инициализируются, пока не будут созданы 2 основных потока.
  • Поскольку выполнение задачи занимает 10 секунд, задачи будут постепенно накапливаться в очереди, а задачи будут постепенно накапливаться до 10.
  • Затем пул потоков будет продолжать добавлять новые потоки, пока максимальное количество потоков не станет равным 5.
  • Когда максимальное количество потоков равно 5, очередь также заполняется до 10. В это время возникнет исключение, которое отказывается выполняться, если есть поступающие задачи.

Мы знаем, что пул потоков Java по умолчанию предпочитает использовать очереди для хранения задач, а не использовать больше потоков для обработки задач. Только когда очередь заполнена, для временной обработки внезапных изменений будет использоваться больше пулов потоков. Выдается больше задач. Иногда мы на самом деле предпочитаем более агрессивный подход, когда пул потоков отдает приоритет открытию большего количества потоков, а вместо этого использует очередь в качестве резервного решения. Например, в нашем примере выполнение задачи очень медленное, занимает 10 секунд, и одна задача отправляется каждую секунду, если пул потоков может быть эластичным до 5 максимальных потоков, то 5 задач будут выполняться через 20 секунд, 5 задач были завершены, и 10 находятся в пуле потоков, и эти задачи могут быть выполнены в конечном итоге вместо медленных задач, которые слишком поздно обрабатывать из-за позднего расширения пула потоков.

Мы можем сделать это путем взлома:

@Test
public void test2() throws InterruptedException {
    AtomicInteger atomicInteger = new AtomicInteger();

    BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(10) {
        @Override
        public boolean offer(Runnable e) {
            return false;
        }
    };

    ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
            2, 5,
            5, TimeUnit.SECONDS,
            queue, new ThreadFactoryImpl("elastic-pool"), (r, executor) -> {
        try {
            executor.getQueue().put(r);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    });

    threadPool.allowCoreThreadTimeOut(true);
    printStats(threadPool);
    submitTasks(atomicInteger,threadPool);
    threadPool.shutdown();
    threadPool.awaitTermination(1, TimeUnit.HOURS);
}

Реализация этой функции в основном зависит от улучшений в двух местах:

  • Нам нужно переписать метод предложения очереди и вернуть false напрямую, что создаст у пула потоков иллюзию того, что очередь заполнена.Определение метода предложения выглядит следующим образом:
    image_1dfkia9vgapk1k99pve1teelc99.png-133.3kB
  • Предоставьте собственный обработчик отклонения при инициализации пула потоков. В это время (когда будет достигнуто максимальное количество потоков) мы фактически вставим задачу в очередь. RejectedExecutionHandler определяется следующим образом:
    image_1dfkieh9k30l30o1hd210aseilm.png-186.3kB

Давайте посмотрим на вывод:

10:53:37.889 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:37.898 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 0
10:53:37.901 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 0
10:53:37.901 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 0
10:53:37.901 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 0
10:53:37.901 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:38.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:38.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 0
10:53:38.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 0
10:53:38.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 0
10:53:38.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 0
10:53:38.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:38.919 [elastic-pool1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 1 started
10:53:39.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:39.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 1
10:53:39.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 1
10:53:39.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 0
10:53:39.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 0
10:53:39.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:39.924 [elastic-pool2] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 2 started
10:53:40.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:40.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 2
10:53:40.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 2
10:53:40.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 0
10:53:40.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 0
10:53:40.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:40.930 [elastic-pool3] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 3 started
10:53:41.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:41.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 3
10:53:41.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 3
10:53:41.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 0
10:53:41.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 0
10:53:41.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:41.934 [elastic-pool4] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 4 started
10:53:42.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:42.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 4
10:53:42.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 4
10:53:42.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 0
10:53:42.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 0
10:53:42.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:42.935 [elastic-pool5] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 5 started
10:53:43.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:43.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
10:53:43.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
10:53:43.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 0
10:53:43.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 0
10:53:43.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:44.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:44.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
10:53:44.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
10:53:44.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 0
10:53:44.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 1
10:53:44.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:45.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:45.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
10:53:45.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
10:53:45.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 0
10:53:45.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 2
10:53:45.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:46.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:46.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
10:53:46.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
10:53:46.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 0
10:53:46.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 3
10:53:46.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:47.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:47.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
10:53:47.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
10:53:47.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 0
10:53:47.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 4
10:53:47.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:48.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:48.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
10:53:48.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
10:53:48.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 0
10:53:48.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 5
10:53:48.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:48.921 [elastic-pool1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 1 finished
10:53:48.922 [elastic-pool1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 6 started
10:53:49.882 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:49.882 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
10:53:49.882 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
10:53:49.882 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 1
10:53:49.882 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 5
10:53:49.883 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:49.927 [elastic-pool2] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 2 finished
10:53:49.928 [elastic-pool2] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 7 started
10:53:50.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:50.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
10:53:50.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
10:53:50.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 2
10:53:50.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 5
10:53:50.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:50.933 [elastic-pool3] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 3 finished
10:53:50.933 [elastic-pool3] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 8 started
10:53:51.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:51.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
10:53:51.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
10:53:51.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 3
10:53:51.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 5
10:53:51.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:51.935 [elastic-pool4] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 4 finished
10:53:51.935 [elastic-pool4] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 9 started
10:53:52.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:52.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
10:53:52.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
10:53:52.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 4
10:53:52.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 5
10:53:52.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:52.937 [elastic-pool5] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 5 finished
10:53:52.938 [elastic-pool5] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 10 started
10:53:53.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:53.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
10:53:53.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
10:53:53.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 5
10:53:53.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 5
10:53:53.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:54.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:54.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
10:53:54.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
10:53:54.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 5
10:53:54.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 6
10:53:54.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:55.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:55.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
10:53:55.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
10:53:55.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 5
10:53:55.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 7
10:53:55.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:56.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:56.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
10:53:56.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
10:53:56.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 5
10:53:56.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 8
10:53:56.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:57.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:57.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
10:53:57.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
10:53:57.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 5
10:53:57.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 9
10:53:57.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:58.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:58.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
10:53:58.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
10:53:58.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 5
10:53:58.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 10
10:53:58.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:58.923 [elastic-pool1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 6 finished
10:53:58.923 [elastic-pool1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 11 started
10:53:59.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:59.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
10:53:59.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
10:53:59.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 6
10:53:59.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 9
10:53:59.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:53:59.931 [elastic-pool2] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 7 finished
10:53:59.931 [elastic-pool2] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 12 started
10:54:00.883 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:00.883 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
10:54:00.883 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
10:54:00.883 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 7
10:54:00.883 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 8
10:54:00.883 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:00.937 [elastic-pool3] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 8 finished
10:54:00.938 [elastic-pool3] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 13 started
10:54:01.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:01.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
10:54:01.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
10:54:01.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 8
10:54:01.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 7
10:54:01.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:01.937 [elastic-pool4] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 9 finished
10:54:01.937 [elastic-pool4] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 14 started
10:54:02.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:02.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
10:54:02.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
10:54:02.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 9
10:54:02.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 6
10:54:02.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:02.941 [elastic-pool5] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 10 finished
10:54:02.941 [elastic-pool5] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 15 started
10:54:03.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:03.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
10:54:03.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
10:54:03.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 10
10:54:03.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 5
10:54:03.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:04.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:04.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
10:54:04.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
10:54:04.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 10
10:54:04.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 5
10:54:04.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:05.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:05.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
10:54:05.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
10:54:05.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 10
10:54:05.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 5
10:54:05.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:06.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:06.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
10:54:06.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
10:54:06.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 10
10:54:06.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 5
10:54:06.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:07.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:07.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
10:54:07.882 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
10:54:07.882 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 10
10:54:07.882 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 5
10:54:07.882 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:08.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:08.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
10:54:08.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
10:54:08.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 10
10:54:08.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 5
10:54:08.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:08.927 [elastic-pool1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 11 finished
10:54:08.928 [elastic-pool1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 16 started
10:54:09.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:09.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
10:54:09.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
10:54:09.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 11
10:54:09.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 4
10:54:09.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:09.933 [elastic-pool2] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 12 finished
10:54:09.933 [elastic-pool2] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 17 started
10:54:10.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:10.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
10:54:10.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
10:54:10.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 12
10:54:10.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 3
10:54:10.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:10.942 [elastic-pool3] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 13 finished
10:54:10.942 [elastic-pool3] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 18 started
10:54:11.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:11.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
10:54:11.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
10:54:11.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 13
10:54:11.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 2
10:54:11.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:11.939 [elastic-pool4] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 14 finished
10:54:11.939 [elastic-pool4] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 19 started
10:54:12.881 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:12.882 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
10:54:12.882 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
10:54:12.882 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 14
10:54:12.882 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 1
10:54:12.882 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:12.946 [elastic-pool5] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 15 finished
10:54:12.946 [elastic-pool5] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 20 started
10:54:13.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:13.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
10:54:13.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
10:54:13.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 15
10:54:13.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 0
10:54:13.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:14.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:14.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
10:54:14.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
10:54:14.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 15
10:54:14.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 0
10:54:14.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:15.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:15.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
10:54:15.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
10:54:15.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 15
10:54:15.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 0
10:54:15.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:16.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:16.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
10:54:16.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
10:54:16.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 15
10:54:16.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 0
10:54:16.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:17.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:17.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
10:54:17.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
10:54:17.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 15
10:54:17.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 0
10:54:17.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:18.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:18.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 5
10:54:18.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 5
10:54:18.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 15
10:54:18.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 0
10:54:18.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:18.929 [elastic-pool1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 16 finished
10:54:19.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:19.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 4
10:54:19.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 4
10:54:19.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 16
10:54:19.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 0
10:54:19.880 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:19.938 [elastic-pool2] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 17 finished
10:54:20.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:20.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 3
10:54:20.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 3
10:54:20.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 17
10:54:20.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 0
10:54:20.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:20.947 [elastic-pool3] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 18 finished
10:54:21.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:21.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 2
10:54:21.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 2
10:54:21.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 18
10:54:21.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 0
10:54:21.879 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:21.943 [elastic-pool4] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 19 finished
10:54:22.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:22.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Pool Size: 1
10:54:22.877 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Active Threads: 1
10:54:22.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks Completed: 19
10:54:22.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - Number of Tasks in Queue: 0
10:54:22.878 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - =========================
10:54:22.950 [elastic-pool5] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.ThreadPoolExecutorTest - 20 finished

Из этого результата вы можете увидеть:

  • В начале, поскольку пул потоков не был предварительно инициализирован, в нем по-прежнему было 0 потоков.
  • Затем напрямую вытянули на максимальную нить 5 нитей
  • Все задачи можно выполнить
  • Наконец, поскольку мы включили allowCoreThreadTimeOut, основной поток также может быть перезапущен.

На самом деле тут можно придумать другую идею.Так как мы надеемся, что в случае высокого параллелизма пул потоков может создавать потоки более активно, то мы можем также инициализировать 5 основных потоков и 5 максимальных потоков при инициализации пула потоков.Тогда включить повторное использование основного потока, что также может сохранить потоки при низком уровне параллелизма.

Конечно реализация тут очень простая и грубая.На самом деле когда очередь возвращает false это своего рода знание.Нам лучше иметь некий буфер.Если нет-создавайте новый поток,и не обязательно возвращать false напрямую как здесь. Мы сделаем это позже. Упомянем лучшую реализацию пула потоков tomcat.

Назовите потоки пула потоков

В предыдущем тесте мы использовали пользовательский класс фабрики потоков, чтобы назвать поток:

public class ThreadFactoryImpl implements ThreadFactory {
    private final AtomicLong threadIndex = new AtomicLong(0);
    private final String threadNamePrefix;
    private final boolean daemon;

    public ThreadFactoryImpl(final String threadNamePrefix) {
        this(threadNamePrefix, false);
    }

    public ThreadFactoryImpl(final String threadNamePrefix, boolean daemon) {
        this.threadNamePrefix = threadNamePrefix;
        this.daemon = daemon;
    }

    @Override
    public Thread newThread(Runnable r) {
        Thread thread = new Thread(r, threadNamePrefix + this.threadIndex.incrementAndGet());
        thread.setDaemon(daemon);
        return thread;
    }
}

Это очень хорошая практика.Для сложных проектов пулов потоков должно быть больше, чем N. С четкими и легко идентифицируемыми именами легче устранять неполадки при возникновении проблем.

Пул потоков Tomcat

В пул потоков Tomcat были внесены некоторые улучшения на основе собственного пула потоков, в основном в трех аспектах:

  • Инициализируйте основные потоки в начале, и эти потоки обязательно заполнятся позже, так почему бы не инициализировать в начале?
  • Как и прежде, мы будем использовать как можно больше потоков вместо того, чтобы сначала использовать очередь (очередь tomcat — бесконечная очередь, поэтому это гарантирует, что можно использовать самый большой поток, иначе конфигурация самого большого потока не имеет смысла)
  • Когда возникает исключение сбоя отправки задачи, когда очередь заполнена, сделайте последнюю попытку, отправьте задачу в очередь и подождите определенное время ожидания.

Взгляните на соответствующий код ниже: Во-первых, это очередь, мы сосредоточимся на переписанном методе предложения и вернем false, чтобы увеличить время потока:

@Slf4j
public class TomcatTaskQueue extends LinkedBlockingQueue<Runnable> {

private transient volatile TomcatThreadPool parent = null;

public TomcatTaskQueue(int capacity) {
    super(capacity);
}

public void setParent(TomcatThreadPool tp) {
    parent = tp;
}

public boolean force(Runnable o) {
    if (parent == null || parent.isShutdown())
        throw new RejectedExecutionException("taskQueue.notRunning");
    return super.offer(o); //forces the item onto the queue, to be used if the task is rejected
}

public boolean force(Runnable o, long timeout, TimeUnit unit) throws InterruptedException {
    if (parent == null || parent.isShutdown())
        throw new RejectedExecutionException("taskQueue.notRunning");
    return super.offer(o, timeout, unit); //forces the item onto the queue, to be used if the task is rejected
}

@Override
public boolean offer(Runnable o) {
    //we can't do any checks
    if (parent == null)
        return super.offer(o);
    //we are maxed out on threads, simply queue the object
    if (parent.getPoolSize() == parent.getMaximumPoolSize()) {
        log.info("pool==max, getPoolSize: {}, getMaximumPoolSize:{}, task:{}", parent.getPoolSize(), parent.getMaximumPoolSize(), o);
        return super.offer(o);
    }
    //we have idle threads, just add it to the queue
    if (parent.getSubmittedCount() <= (parent.getPoolSize())) {
        log.info("submit<=pool, getPoolSize: {}, getMaximumPoolSize:{}, task:{}", parent.getPoolSize(), parent.getMaximumPoolSize(), o);
        return super.offer(o);
    }
    //if we have less threads than maximum force creation of a new thread
    if (parent.getPoolSize() < parent.getMaximumPoolSize()) {
        log.info("Grow thread pool, getPoolSize: {}, getMaximumPoolSize:{}", parent.getPoolSize(), parent.getMaximumPoolSize());
        return false;
    }
    //if we reached here, we need to add it to the queue
    log.info("else, getPoolSize: {}, getMaximumPoolSize:{}, task:{}", parent.getPoolSize(), parent.getMaximumPoolSize(), o);
    return super.offer(o);
}

Затем идет пул потоков, мы фокусируемся на стратегии обработки после отклонения исключений:

@Slf4j
public class TomcatThreadPool extends java.util.concurrent.ThreadPoolExecutor {

    /**
     * The number of tasks submitted but not yet finished. This includes tasks
     * in the queue and tasks that have been handed to a worker thread but the
     * latter did not start executing the task yet.
     * This number is always greater or equal to {@link #getActiveCount()}.
     */
    private final AtomicInteger submittedCount = new AtomicInteger(0);

    public TomcatThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
        prestartAllCoreThreads();
    }

    public TomcatThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,
                            RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
        prestartAllCoreThreads();
    }

    public TomcatThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, new RejectHandler());
        prestartAllCoreThreads();
    }

    public TomcatThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, new RejectHandler());
        prestartAllCoreThreads();
    }

    public int getSubmittedCount() {
        return submittedCount.get();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void execute(Runnable command) {
        execute(command, 0, TimeUnit.MILLISECONDS);
    }

    /**
     * Executes the given command at some time in the future.  The command
     * may execute in a new thread, in a pooled thread, or in the calling
     * thread, at the discretion of the <tt>Executor</tt> implementation.
     * If no threads are available, it will be added to the work queue.
     * If the work queue is full, the system will wait for the specified
     * time and it throw a RejectedExecutionException if the queue is still
     * full after that.
     *
     * @param command the runnable task
     * @param timeout A timeout for the completion of the task
     * @param unit    The timeout time unit
     * @throws RejectedExecutionException if this task cannot be
     *                                    accepted for execution - the queue is full
     * @throws NullPointerException       if command or unit is null
     */
    public void execute(Runnable command, long timeout, TimeUnit unit) {
        submittedCount.incrementAndGet();
        try {
            super.execute(command);
        } catch (RejectedExecutionException rx) {
            if (super.getQueue() instanceof TomcatTaskQueue) {
                final TomcatTaskQueue queue = (TomcatTaskQueue) super.getQueue();
                try {
                    if (!queue.force(command, timeout, unit)) {
                        submittedCount.decrementAndGet();
                        throw new RejectedExecutionException("threadPoolExecutor.queueFull");
                    } else {
                        log.warn("RejectedExecutionException throw, task {} put into queue again", command.toString());
                    }
                } catch (InterruptedException x) {
                    submittedCount.decrementAndGet();
                    throw new RejectedExecutionException(x);
                }
            } else {
                submittedCount.decrementAndGet();
                throw rx;
            }

        }
    }

    private static class RejectHandler implements RejectedExecutionHandler {
        @Override
        public void rejectedExecution(Runnable r,
                                      java.util.concurrent.ThreadPoolExecutor executor) {
            throw new RejectedExecutionException();
        }

    }
}

Теперь давайте напишем тестовый код:

@Slf4j
public class TomcatThreadPoolTest {

    @Test
    public void test() throws InterruptedException {
        TomcatTaskQueue taskqueue = new TomcatTaskQueue(5);
        TomcatThreadPool threadPool = new TomcatThreadPool(2, 5, 60, TimeUnit.SECONDS, taskqueue);
        taskqueue.setParent(threadPool);
        IntStream.rangeClosed(1, 10).forEach(i -> threadPool.execute(new Task(true, i)));
        IntStream.rangeClosed(1, 10).forEach(i -> threadPool.execute(new Task(false, i)
                , 1050, TimeUnit.MILLISECONDS));

        threadPool.shutdown();
        threadPool.awaitTermination(1, TimeUnit.HOURS);
    }

    @ToString
    class Task implements Runnable {
        private boolean slow;
        private String name;

        public Task(boolean slow, int index) {
            this.slow = slow;
            this.name = String.format("%s-%d", slow ? "slow" : "quick", index);
        }

        @Override
        public void run() {
            log.info("Start:{}", name);
            if (slow) {
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            log.info("Finish:{}", name);
        }
    }
}

В тестовом коде наша очередь составляет всего 5, наш максимальный поток также равен 5, а наша медленная задача равна 10, потому что нашей задаче разрешено ждать 1050 мс, чтобы попытаться отправить в очередь, поэтому на основе этой конфигурации наша быстрая задача также может быть успешно выполнено без ошибок:

16:38:36.117 [main] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatTaskQueue - submit<=pool, getPoolSize: 2, getMaximumPoolSize:5, task:TomcatThreadPoolTest.Task(slow=true, name=slow-1)
16:38:36.165 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Start:slow-1
16:38:36.166 [main] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatTaskQueue - submit<=pool, getPoolSize: 2, getMaximumPoolSize:5, task:TomcatThreadPoolTest.Task(slow=true, name=slow-2)
16:38:36.166 [pool-1-thread-2] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Start:slow-2
16:38:36.166 [main] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatTaskQueue - Grow thread pool, getPoolSize: 2, getMaximumPoolSize:5
16:38:36.166 [pool-1-thread-3] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Start:slow-3
16:38:36.166 [main] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatTaskQueue - Grow thread pool, getPoolSize: 3, getMaximumPoolSize:5
16:38:36.167 [pool-1-thread-4] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Start:slow-4
16:38:36.167 [main] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatTaskQueue - Grow thread pool, getPoolSize: 4, getMaximumPoolSize:5
16:38:36.167 [pool-1-thread-5] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Start:slow-5
16:38:36.168 [main] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatTaskQueue - pool==max, getPoolSize: 5, getMaximumPoolSize:5, task:TomcatThreadPoolTest.Task(slow=true, name=slow-6)
16:38:36.168 [main] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatTaskQueue - pool==max, getPoolSize: 5, getMaximumPoolSize:5, task:TomcatThreadPoolTest.Task(slow=true, name=slow-7)
16:38:36.168 [main] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatTaskQueue - pool==max, getPoolSize: 5, getMaximumPoolSize:5, task:TomcatThreadPoolTest.Task(slow=true, name=slow-8)
16:38:36.169 [main] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatTaskQueue - pool==max, getPoolSize: 5, getMaximumPoolSize:5, task:TomcatThreadPoolTest.Task(slow=true, name=slow-9)
16:38:36.169 [main] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatTaskQueue - pool==max, getPoolSize: 5, getMaximumPoolSize:5, task:TomcatThreadPoolTest.Task(slow=true, name=slow-10)
16:38:36.170 [main] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatTaskQueue - pool==max, getPoolSize: 5, getMaximumPoolSize:5, task:TomcatThreadPoolTest.Task(slow=false, name=quick-1)
16:38:37.169 [pool-1-thread-2] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Finish:slow-2
16:38:37.169 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Finish:slow-1
16:38:37.169 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Start:slow-7
16:38:37.169 [pool-1-thread-2] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Start:slow-6
16:38:37.169 [main] WARN me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPool - RejectedExecutionException throw, task TomcatThreadPoolTest.Task(slow=false, name=quick-1) put into queue again
16:38:37.169 [main] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatTaskQueue - pool==max, getPoolSize: 5, getMaximumPoolSize:5, task:TomcatThreadPoolTest.Task(slow=false, name=quick-2)
16:38:37.170 [main] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatTaskQueue - pool==max, getPoolSize: 5, getMaximumPoolSize:5, task:TomcatThreadPoolTest.Task(slow=false, name=quick-3)
16:38:37.170 [pool-1-thread-4] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Finish:slow-4
16:38:37.170 [pool-1-thread-3] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Finish:slow-3
16:38:37.170 [pool-1-thread-5] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Finish:slow-5
16:38:37.170 [pool-1-thread-4] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Start:slow-8
16:38:37.170 [main] WARN me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPool - RejectedExecutionException throw, task TomcatThreadPoolTest.Task(slow=false, name=quick-3) put into queue again
16:38:37.170 [pool-1-thread-5] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Start:slow-10
16:38:37.170 [pool-1-thread-3] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Start:slow-9
16:38:37.171 [main] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatTaskQueue - pool==max, getPoolSize: 5, getMaximumPoolSize:5, task:TomcatThreadPoolTest.Task(slow=false, name=quick-4)
16:38:37.171 [main] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatTaskQueue - pool==max, getPoolSize: 5, getMaximumPoolSize:5, task:TomcatThreadPoolTest.Task(slow=false, name=quick-5)
16:38:37.171 [main] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatTaskQueue - pool==max, getPoolSize: 5, getMaximumPoolSize:5, task:TomcatThreadPoolTest.Task(slow=false, name=quick-6)
16:38:38.171 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Finish:slow-7
16:38:38.171 [pool-1-thread-2] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Finish:slow-6
16:38:38.172 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Start:quick-1
16:38:38.172 [main] WARN me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPool - RejectedExecutionException throw, task TomcatThreadPoolTest.Task(slow=false, name=quick-6) put into queue again
16:38:38.172 [pool-1-thread-2] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Start:quick-2
16:38:38.172 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Finish:quick-1
16:38:38.172 [pool-1-thread-2] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Finish:quick-2
16:38:38.172 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Start:quick-3
16:38:38.172 [pool-1-thread-2] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Start:quick-4
16:38:38.172 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Finish:quick-3
16:38:38.172 [pool-1-thread-2] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Finish:quick-4
16:38:38.172 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Start:quick-5
16:38:38.172 [main] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatTaskQueue - pool==max, getPoolSize: 5, getMaximumPoolSize:5, task:TomcatThreadPoolTest.Task(slow=false, name=quick-7)
16:38:38.172 [pool-1-thread-2] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Start:quick-6
16:38:38.172 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Finish:quick-5
16:38:38.172 [pool-1-thread-2] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Finish:quick-6
16:38:38.172 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Start:quick-7
16:38:38.172 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Finish:quick-7
16:38:38.172 [main] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatTaskQueue - pool==max, getPoolSize: 5, getMaximumPoolSize:5, task:TomcatThreadPoolTest.Task(slow=false, name=quick-8)
16:38:38.173 [pool-1-thread-2] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Start:quick-8
16:38:38.173 [pool-1-thread-2] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Finish:quick-8
16:38:38.173 [main] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatTaskQueue - pool==max, getPoolSize: 5, getMaximumPoolSize:5, task:TomcatThreadPoolTest.Task(slow=false, name=quick-9)
16:38:38.173 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Start:quick-9
16:38:38.173 [pool-1-thread-1] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Finish:quick-9
16:38:38.173 [main] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatTaskQueue - pool==max, getPoolSize: 5, getMaximumPoolSize:5, task:TomcatThreadPoolTest.Task(slow=false, name=quick-10)
16:38:38.173 [pool-1-thread-2] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Start:quick-10
16:38:38.174 [pool-1-thread-2] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Finish:quick-10
16:38:38.175 [pool-1-thread-4] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Finish:slow-8
16:38:38.175 [pool-1-thread-3] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Finish:slow-9
16:38:38.175 [pool-1-thread-5] INFO me.josephzhu.javaconcurrenttest.concurrent.executors.TomcatThreadPoolTest - Finish:slow-10

Обратите внимание, что в журнале есть несколько исключений RejectedExecutionException, но все ожидающие задачи отправляются в очередь.

предопределенный пул потоков

Давайте посмотрим на два так называемых предопределенных Исполнителя.Обычно используетсяПул потоков:

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
    }
public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}
    

Так называемый пул потоков фиксированного размера означает, что размер потока фиксирован, но очередь не ограничена. Очевидно, что если задач слишком много и они очень медленные, чтобы превысить вычислительную мощность пула потоков и накапливаться, то эта неограниченная очередь может привести к OOM.Это риск:

image_1dflmvolmfc7122k17841ut61tnj79.png-359.3kB

Существует также так называемый пул кэш-потоков.Этот кеш означает, что поток кешируется и перезапускается за 60 секунд. Он будет создан при необходимости. Количество потоков неограничено, и он будет создаваться все время, если это необходимо. Это также экстремально и может создать слишком много потоков, снова вызывая OOM:

image_1dflftfnmr651qbnfrsrs21je06s.png-364.1kB

Код теста не дается, вы можете проводить свои эксперименты. Поэтому руководство Ali Java Development Manual не рекомендует использовать эти два предопределенных пула потоков, мы должны управлять пулами потоков в соответствии с нашими потребностями:

  • тип очереди
  • длина очереди
  • количество основных потоков
  • максимальное количество потоков
  • время восстановления
  • Следует ли перерабатывать основные потоки
  • Нужно ли предварительно создавать основные потоки
  • отказ в обработке
  • фабрика ниток

Приостанавливаемый пул потоков

Здесь мы приводим официальный пример реализации пула потоков с паузой путем реализации пользовательского метода beforeExecute.

image_1dfl8ntbk155rpm71f3c1o8r15et13.png-143kB

Код пула потоков выглядит следующим образом:

public class PausableThreadPoolExecutor extends ThreadPoolExecutor {
    private boolean isPaused;
    private ReentrantLock pauseLock = new ReentrantLock();
    private Condition unpaused = pauseLock.newCondition();

    public PausableThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }

    public PausableThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
    }

    public PausableThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
    }

    public PausableThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
    }
    
    @Override
    protected void beforeExecute(Thread t, Runnable r) {
        super.beforeExecute(t, r);
        pauseLock.lock();
        try {
            while (isPaused) unpaused.await();
        } catch (InterruptedException ie) {
            t.interrupt();
        } finally {
            pauseLock.unlock();
        }
    }

    public void pause() {
        pauseLock.lock();
        try {
            isPaused = true;
        } finally {
            pauseLock.unlock();
        }
    }

    public void resume() {
        pauseLock.lock();
        try {
            isPaused = false;
            unpaused.signalAll();
        } finally {
            pauseLock.unlock();
        }
    }
}

Напишите тестовый код, чтобы попробовать:

@Test
public void test() throws InterruptedException {
    PausableThreadPoolExecutor threadPool = new PausableThreadPoolExecutor(1,1,0,TimeUnit.HOURS,new LinkedBlockingQueue<>());
    IntStream.rangeClosed(1, 5).forEach(i->threadPool.submit(()->{
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("I'm done : {}", i);
    }));
    ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
    scheduler.schedule(threadPool::pause, 2, TimeUnit.SECONDS);
    scheduler.schedule(threadPool::resume, 4, TimeUnit.SECONDS);

    threadPool.shutdown();
    threadPool.awaitTermination(1, TimeUnit.HOURS);
}

В тестовом коде наш пул потоков имеет только один поток, мы отправляем в него пять задач, и каждая задача должна выполняться в течение 1 секунды, мы используем другой пул потоков задач по времени, чтобы регулярно переключать этот пул потоков с паузой. Результаты приведены ниже:

image_1dfl9f4lt1e45a581ob11bqa4hr37.png-197.3kB
Как видите, этот пул потоков возобновился после 2-секундной паузы на 4 секунды.

Пул запланированных задач

Только что в тесте мы использовали пул потоков задач по времени, здесь мы проводим еще один тест. Давайте проверим разницу между scheduleAtFixedRate и scheduleWithFixedDelay. В приведенном ниже коде мы запускаем два теста по отдельности:

  • Один раз для выполнения задачи с фиксированной частотой и один раз для выполнения задачи с фиксированной задержкой.
  • Затем закройте пул потоков задач по времени через 1 секунду (это также достигается с помощью функции планирования этой задачи по времени).
  • Основной поток ожидает завершения работы пула потоков.
@Test
public void test1() throws InterruptedException {
    AtomicInteger scheduleAtFixedRateTotal = new AtomicInteger();
    ScheduledExecutorService scheduleAtFixedRateExecutorService = Executors.newSingleThreadScheduledExecutor();
    ScheduledFuture scheduleAtFixedRateTotalFuture = scheduleAtFixedRateExecutorService.scheduleAtFixedRate(() -> {
        try {
            TimeUnit.MILLISECONDS.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("scheduleAtFixedRate:" + scheduleAtFixedRateTotal.incrementAndGet());
    }, 0, 100, TimeUnit.MILLISECONDS);
    scheduleAtFixedRateExecutorService.schedule(() -> scheduleAtFixedRateTotalFuture.cancel(false), 1, TimeUnit.SECONDS);
    while (!scheduleAtFixedRateTotalFuture.isDone()) TimeUnit.MILLISECONDS.sleep(1);
    Assert.assertEquals(11, scheduleAtFixedRateTotal.get());

    AtomicInteger scheduleWithFixedDelayTotal = new AtomicInteger();
    ScheduledExecutorService scheduleWithFixedDelayExecutorService = Executors.newSingleThreadScheduledExecutor();
    ScheduledFuture scheduleWithFixedDelayFuture = scheduleWithFixedDelayExecutorService.scheduleWithFixedDelay(() -> {
        try {
            TimeUnit.MILLISECONDS.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("scheduleWithFixedDelay:" + scheduleWithFixedDelayTotal.incrementAndGet());
    }, 0, 100, TimeUnit.MILLISECONDS);
    scheduleWithFixedDelayExecutorService.schedule(() -> scheduleWithFixedDelayFuture.cancel(false), 1, TimeUnit.SECONDS);
    while (!scheduleWithFixedDelayFuture.isDone()) TimeUnit.MILLISECONDS.sleep(1);
    Assert.assertEquals(5, scheduleWithFixedDelayTotal.get());
}

Благодаря утверждению мы также можем узнать, что выполнение задачи с фиксированной частотой ** «игнорирует» ** время выполнения задачи, поэтому ее можно выполнять больше раз и, наконец, выполнить 11 раз за 1 секунду. Задача выполнения с фиксированной задержкой заключается в задержке выполнения фиксированного интервала после завершения задачи и, наконец, может выполняться только 5 раз примерно за 1 секунду. Вот результат:

image_1dfl9s69u19tgh3s10r911j21t5g3k.png-520.1kB

Здесь, не обращая внимания на два слова, я поставил двойные кавычки, потому что для однопоточного пула потоков с синхронизацией задачи, если выполнение задачи слишком медленное, медленнее, чем частота, то пул потоков не имеет возможности fixRate исполнение. Здесь можно попробовать изменить время сна со 100 мс на 200 мс, после повторного запуска результат такой:

image_1dfladh1p1k721fl31dc1tuv1t1e41.png-367.4kB
Какие? Модульные тесты все еще проходят? Разве это не должно закончиться после 5 прогонов? Обратите внимание, что наш пул потоков не закончился через 1 секунду, а длился более 2 секунд, что все еще является старой проблемой.Поскольку это один поток, наша задача по закрытию пула потоков не может быть выполнена вовремя. Попробуйте изменить код и поместить задачу отмены в отдельный пул потоков для выполнения:

Executors.newSingleThreadScheduledExecutor().schedule(() -> scheduleAtFixedRateTotalFuture.cancel(false), 1, TimeUnit.SECONDS);

(Или вы также можете использовать пул потоков задач с 2 потоками) Как видите, на этот раз результат ожидаемый:

image_1dflam0bu12d21qik532581163n4e.png-162.3kB

Пул потоков ForkJoin

Начиная с Java 1.8, исполнители предоставляют newWorkStealingPool для получения пула потоков ForkJoin. Как видно из названия, это work-stealing thread pool.Традиционный пул потоков имеет общую очередь задач.Когда задач много и задачи выполняются быстро (задачи с интенсивным использованием процессора), будет больше конкуренции проблемам. , и ForkJoin каждый поток имеет свою очередь задач.Если в своей очереди нет задачи, он может воровать задачи из других очередей, что обеспечивает пропускную способность и снижает конкуренцию. Напишем кусок кода для сравнения:

image_1dflb1rdqa2q34inem1mb8end4r.png-194.3kB

@Slf4j
public class ForkJoinPoolBenchmark {
    @Test
    public void test() throws InterruptedException {
        AtomicLong atomicLong = new AtomicLong();
        StopWatch stopWatch = new StopWatch();
        ExecutorService normal = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
        ExecutorService forkjoin = Executors.newWorkStealingPool(Runtime.getRuntime().availableProcessors());

        stopWatch.start("normal");
        LongStream.rangeClosed(1, 10000000).forEach(__->normal.submit(atomicLong::incrementAndGet));
        normal.shutdown();
        normal.awaitTermination(1, TimeUnit.HOURS);
        stopWatch.stop();
        long r = atomicLong.get();
        stopWatch.start("forkjoin");
        LongStream.rangeClosed(1, 10000000).forEach(__->forkjoin.submit(atomicLong::incrementAndGet));
        forkjoin.shutdown();
        forkjoin.awaitTermination(1, TimeUnit.HOURS);
        stopWatch.stop();
        log.info(stopWatch.prettyPrint());
        log.info("result:{},{}", r, atomicLong.get());
    }
}

Здесь наша задача состоит в том, чтобы просто непрерывно++ использовать AtomicLong. Результаты теста следующие:

image_1dflbna1ncr2484ter12m7sir58.png-116.8kB
Как видите, очевидно, что forkjoin работает быстрее.

Что происходит, когда в задаче пула потоков возникает исключение?

Часто обнаруживается, что некоторые мелкие партнеры пишут код.После отправки задачи в пул потоков задача часто выдает исключение, независимо от исключения.Говорят, что все в порядке, и пул потоков перехватит исключение. Это действительно так? Попробуйте написать кусок кода:

@Slf4j
public class ThreadPoolExceptionTest {

    @Before
    public void setDefaultUncaughtExceptionHandler(){
        Thread.setDefaultUncaughtExceptionHandler((Thread t, Throwable e)->{
            log.warn("Exception in thread {}", t,e);
        });
    }

    @Test
    public void test() throws InterruptedException {
        String prefix = "test";
        ExecutorService threadPool = Executors.newFixedThreadPool(1, new ThreadFactoryImpl(prefix));
        IntStream.rangeClosed(1, 10).forEach(i -> threadPool.execute(() -> {
            if (i == 5) throw new RuntimeException("error");
            log.info("I'm done : {}", i);
            if (i < 5) Assert.assertEquals(prefix + "1", Thread.currentThread().getName());
            else Assert.assertEquals(prefix + "2", Thread.currentThread().getName());
        }));

        threadPool.shutdown();
        threadPool.awaitTermination(1, TimeUnit.HOURS);
    }
}

Здесь у нас всего задач 10. При выполнении пятой задачи будет активно выбрасываться исключение. Как видно из утверждения, начальная задача выполняется в потоке test1, потому что задача после исключения выполняется в потоке test2, и смотрим на результат выполнения:

image_1dflca9f9rdi4iiqbaj4m2bk5l.png-389.5kB
Из результатов также можно сделать несколько выводов:

  • У задачи в пуле потоков есть необработанное исключение.В конце концов, это исключение является необработанным исключением и может быть обработано необработанным исключением.
  • Этот поток завершится, а не пул потоков легенды перехватит исключение
  • Пул потоков может только воссоздавать новые исключения, чтобы заполнить пробелы, что обходится дорого.

Однако этот вывод не совсем верен, попробуем заменить execute на submit:

@Test
public void test() throws InterruptedException {
    String prefix = "test";
    ExecutorService threadPool = Executors.newFixedThreadPool(1, new ThreadFactoryImpl(prefix));
    List<Future> futures = new ArrayList<>();
    IntStream.rangeClosed(1, 10).forEach(i -> futures.add(threadPool.submit(() -> {
        if (i == 5) throw new RuntimeException("error");
        log.info("I'm done : {}", i);
//            if (i < 5) Assert.assertEquals(prefix + "1", Thread.currentThread().getName());
//            else Assert.assertEquals(prefix + "2", Thread.currentThread().getName());
    })));

    for (Future future : futures) {
        try {
            future.get();
        } catch (ExecutionException e) {
            log.warn("future ExecutionException",e);
        }
    }
    threadPool.shutdown();
    threadPool.awaitTermination(1, TimeUnit.HOURS);
}

Результат выглядит следующим образом:

image_1dfld304t1jp4c1og8d13mp3sh62.png-484kB
Вы можете видеть, что на этот раз другое время, исключение будет получено в Future.get(), поэтому поток не умрет. Давайте напишем еще один кусок кода для сравнения производительности (вам нужно аннотировать log.warn в setDefaultUncaughtExceptionHandler, чтобы избежать вывода исключений):

@Test
public void test2() throws InterruptedException {
    StopWatch stopWatch = new StopWatch();
    ExecutorService threadPool1 = Executors.newFixedThreadPool(1);
    stopWatch.start("execute");
    IntStream.rangeClosed(1, 100000).forEach(i->threadPool1.execute(()->{
        throw new RuntimeException("error");
    }));
    threadPool1.shutdown();
    threadPool1.awaitTermination(1, TimeUnit.HOURS);
    stopWatch.stop();
    ExecutorService threadPool2 = Executors.newFixedThreadPool(1);
    stopWatch.start("submit");
    IntStream.rangeClosed(1, 100000).forEach(i->threadPool2.submit(()->{
        throw new RuntimeException("error");
    }));
    threadPool2.shutdown();
    threadPool2.awaitTermination(1, TimeUnit.HOURS);
    stopWatch.stop();
    log.info(stopWatch.prettyPrint());
}

Результат выглядит следующим образом:

image_1dfldk31i7h616dgu2odk6clg6f.png-78.1kB
Это еще раз подтверждает упомянутую ранее стоимость повторного создания потоков. Вы также можете проверить это самостоятельно, что произойдет, если задача запланированного пула потоков задач будет ненормальной?

код

Весь код для этой статьи можно найти в моем Github Repo:GitHub.com/Джозеф З Тайгер19…Код протестирован на основе JDK11.

Суммировать

В этой статье мы провели более десяти экспериментов и различных пулов тестовых потоков. Подводя итог, несколько пунктов:

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

  • В крайних случаях может потребоваться изменить поведение пула потоков по умолчанию для создания потоков.

  • Обратите внимание, что лучше не иметь необработанных исключений для задач в пуле потоков.

  • Используйте пул потоков задач по времени для выполнения задач. Обратите внимание на размер пула потоков.