Ограничьте количество потоков и подождите, пока не будет достигнуто максимальное количество потоков, используя аннотацию @Async. - PullRequest
4 голосов
/ 07 мая 2019

Я использую конфигурацию Java Spring с AsyncConfigurer:

@Configuration
@EnableAsync
public class AppConfig implements AsyncConfigurer {

@Override
public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(2);
        executor.setMaxPoolSize(2);
        executor.setQueueCapacity(10);
        executor.setThreadNamePrefix("MyExecutor-");
        executor.initialize();
        return executor;
    }
}

Теперь предположим, что у меня есть метод с аннотацией @Async, и предположим, что он вызывается уже 2 раза, а 2 потока все еще работают. Насколько я понимаю, любой новый вызов к нему будет добавлен в очередь емкостью 10. Теперь, если я получу 11-е задание, каково будет его поведение? будет ли он отклонять задачу, как указано здесь: https://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ThreadPoolExecutor.html? или вызывающая сторона будет ждать, пока слот очереди не освободится?

Мое требование - не превышать фиксированное количество потоков, порожденных с помощью метода @Async, и заставить вызывающего ждать, если будет достигнуто максимальное количество потоков. Будет ли это достигнуто, если я использую ConcurrentTaskExecutor с фиксированным пулом потоков определенного размера?

Ответы [ 2 ]

1 голос
/ 08 мая 2019

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


, я создал Боб Исполнителя следующим образом:

@Bean(name = "CustomAsyncExecutor")
public Executor customThreadPoolTaskExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setCorePoolSize(5);
    executor.setMaxPoolSize(5);
    executor.setQueueCapacity(0);
    executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
    executor.setThreadNamePrefix("Async_Thread_");
    executor.setWaitForTasksToCompleteOnShutdown(true);
    executor.initialize();
    return executor;
}

И затем использовал

@Async("CustomAsyncExecutor")
public void methodName(){
....
}

Учитывая, что когдапотоки заняты, и когда очередь заполнена, новые задачи отклоняются,

executor.setRejectedExecutionHandler (new ThreadPoolExecutor.CallerRunsPolicy ())

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

1 голос
/ 07 мая 2019

В соответствии с тем, как работает ThreadPoolExecutor, 11-е задание будет отклонено, поскольку, когда очередь заполнена, исполнитель пытается увеличить размер пула и, если он не может этого сделать из-за достижения максимального значения, он отклоняет задачу.
Вы можете найти информацию в документации Spring :

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

о вашем требовании:

Мое требование - не превышать установленное количество потоков, созданных с помощью Метод @Async и заставить вызывающего ждать, если максимальное количество потоков достиг. Будет ли это достигнуто, если я использую ConcurrentTaskExecutor с фиксированный пул потоков определенного размера?

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

...