Оптимальный способ создания пула потоков фиксированного размера в Java с использованием сервиса Executors
Я использую Executors
фреймворк в Java для создания пулов потоков для многопоточного приложения, и у меня есть вопрос, связанный с производительностью.
У меня есть приложение, которое может работать в режиме реального времени или не в режиме реального времени. Если это в режиме реального времени, я просто использую следующее:
THREAD_POOL = Executors.newCachedThreadPool();
Но если это не в реальном времени, я хочу иметь возможность контролировать размер моего пула потоков. Чтобы сделать это, я думаю о двух вариантах, но я не совсем понимаю разницу, и какой из них будет работать лучше.
Вариант 1 - использовать простой способ:
THREAD_POOL = Executors.newFixedThreadPool(threadPoolSize);
Вариант 2 - создать свой собственный ThreadPoolExecutor
как это:
RejectedExecutionHandler rejectHandler = new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
try {
executor.getQueue().put(r);
} catch (Exception e) {}
}
};
THREAD_POOL = new ThreadPoolExecutor(threadPoolSize, threadPoolSize, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(10000), rejectHandler);
Я хотел бы понять, в чем преимущество использования более сложного варианта 2, а также, если я должен использовать другую структуру данных, чем LinkedBlockingQueue
? Любая помощь будет оценена.
1 ответ
Глядя на исходный код, вы поймете, что:
Executors.newFixedThreadPool(threadPoolSize);
эквивалентно:
return new ThreadPoolExecutor(threadPoolSize, threadPoolSize, 0L, MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
Так как это не обеспечивает явного RejectedExecutionHandler
, дефолт AbortPolicy
используется. Это в основном кидает RejectedExecutionException
как только очередь заполнится. Но очередь не ограничена, поэтому она никогда не будет полной. Таким образом, этот исполнитель принимает1 ряд заданий.
Ваша декларация намного сложнее и совсем другая:
new LinkedBlockingQueue<Runnable>(10000)
приведет к тому, что пул потоков откажется от задач, если ожидается более 10000.Я не понимаю какой ты
RejectedExecutionHandler
делается. Если пул обнаруживает, он не может поместить больше runnables в очередь, которую он вызывает ваш обработчик. В этом обработчике вы... попробуйте поместить этоRunnable
снова в очередь (котораяпотерпеть неудачу, как в 99% случаевблок). Наконец вы проглотили исключение. Похоже наThreadPoolExecutor.DiscardPolicy
это то, что вы после.Если вы посмотрите на ваши комментарии ниже, то, похоже, вы пытаетесь заблокировать или каким-то образом ограничить клиентов, если очередь задач слишком велика. Я не думаю, что блокировка внутри
RejectedExecutionHandler
хорошая идея Вместо этого рассмотримCallerRunsPolicy
политика отказа. Не совсем то же самое, но достаточно близко.
Подводя итог: если вы хотите ограничить количество ожидающих задач, ваш подход почти хорош. Если вы хотите ограничить количество одновременных потоков, достаточно первого однострочного.
1 - предполагая, что 2^31 - бесконечность