У меня есть приложение SpringBoot, в котором я разрешил не более 45 одновременных запросов.
Теперь 1 запрос в своем пути вызывает 16 внешних служб параллельно с использованием threadPool A
. Поэтому, имея в виду средний и худший случай, я сохранил следующие конфигурации:
ThreadPoolTaskExecutor A = new ThreadPoolTaskExecutor();
A.setCorePoolSize(400);
A.setMaxPoolSize(1000);
A.setQueueCapacity(10);
A.setThreadNamePrefix("async-executor");
A.initialize();
Я ожидал, что не более 45 * 16 = 720 потоков . Но при выполнении нагрузочного теста я заметил, что потоки продолжали открываться (проверено в дампе потоков), и через несколько минут он начал выдавать RejectedExecutionException.
RejectedExecutionException
Task ServiceX rejected from org.springframework.scheduling.concurrent.
ThreadPoolTaskExecutor$1@4221a19e[Running, pool
size = 1000, active threads = 2, queued tasks = 10, completed tasks = 625216]
Большинство потоков, как показано в дампе потоков
"executor-A-57" #579 prio=5 os_prio=0 tid=0x000000000193f800 nid=0x2e95 waiting on condition [0x00007fa9e820c000]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x0000000582dadf90> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
at java.util.concurrent.LinkedBlockingQueue.poll(LinkedBlockingQueue.java:467)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1073)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Locked ownable synchronizers:
- None
Я хотел знать, чего мне здесь не хватает? Почему я получаю отказ?
Редактировать:
Я попытался воспроизвести похожую вещь на коротком куске кода, вот так:
MainClass запускает длинный цикл. Внутри каждого цикла он вызывает сервис1 3 раза. На данный момент у меня есть демо-сервис, который просто имеет внутри тот же код Thread.sleep(100)
.
MainClass.java
package com.flappy.everything.threadpooling;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
public class MainClass {
private static ThreadPoolTaskExecutor getExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setMaxPoolSize(4);
threadPoolTaskExecutor.setThreadNamePrefix("async-exec");
threadPoolTaskExecutor.setCorePoolSize(4);
threadPoolTaskExecutor.setQueueCapacity(2);
threadPoolTaskExecutor.initialize();
return threadPoolTaskExecutor;
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
ThreadPoolTaskExecutor outerExecutor = getExecutor();
List<Service1> services = Arrays.asList(new Service1(), new Service1(), new Service1());
for (int i = 0; i < 1000000; i++) {
List<Future> futures = new ArrayList<>();
for (Service1 service : services) {
futures.add(outerExecutor.submit(() -> {
try {
service.set();
} catch (InterruptedException e) {
e.printStackTrace();
}
}));
}
for (Future future : futures) {
future.get();
}
}
}
}
Service1.java
package com.oyorooms.everything.threadpooling;
import org.springframework.scheduling.annotation.Async;
public class Service1 {
public void set() throws InterruptedException {
Thread.sleep(100);
System.out.println(Thread.currentThread().getName());
}
}
Таким образом, в идеале только 3 потока должны быть открыты для ThreadPool, который я дал, но, тем не менее, я получаю отклонение при запуске кода.