Фабрика Executors от Java использует неограниченную очередь ожидающих задач. Например, Executors.newFixedThreadPool использует new LinkedBlockingQueue, у которого нет ограничений на принятие задач.
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
Когда поступает новая задача и нет доступного потока, она помещается в очередь. Задачи можно добавлять в очередь на неопределенное время, вызывая OutOfMemoryError.
Каков на самом деле сценарий использования этого подхода? Почему создатели Java не использовали ограниченную очередь? Я не могу представить себе сценарий, когда неограниченное лучше ограниченного, но я могу что-то упустить. Может ли кто-нибудь дать достойное объяснение? Лучший!




Вы можете выполнять задачи отклонять, используя ArrayBlockingQueue (ограниченная очередь блокировки)
final BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(100); executorService = new ThreadPoolExecutor(n, n, 0L, TimeUnit.MILLISECONDS, queue);Code above is equivalent to Executors.newFixedThreadPool(n), however instead of default unlimited LinkedBlockingQueue we use ArrayBlockingQueue with fixed capacity of 100. This means that if 100 tasks are already queued (and n being executed), new task will be rejected with RejectedExecutionException.
Это подход по умолчанию, и пользователь может выбрать переход в ограниченную очередь.
Теперь, возможно, ваш вопрос: почему это значение по умолчанию?
На самом деле работать с ограниченными очередями сложнее, что бы вы сделали, если очередь заполнена? Вы бросаете задачу и не принимаете ее? Вы генерируете исключение и завершаете весь процесс ошибкой? Разве это не то, что случилось бы в случае OOM? Таким образом, все это решение должен принимать пользователь, который принимает множество длительных задач, а не является пользователем Java по умолчанию.
Вариант использования неограниченной очереди может быть просто, когда вы ожидаете только небольшое количество выполняющихся одновременных запросов, но вы точно не знаете, сколько, или вы можете реализовать обратное давление на другом этапе вашего приложения, например, для регулирования ваших запросов API.
Можете ли вы привести хорошие примеры, когда неограниченные очереди - разумный подход? Когда разработчик может игнорировать "ограничения" и не заботиться о емкости приложения, его памяти и т. д. Неограниченная очередь в конечном итоге приведет его к OOM или проблемам с производительностью ...
Спасибо, но все равно звучит как искусство, а не наука. Тем не менее, спасибо за вклад
Tasks can be added to the queue indefinitely causing OutOfMemoryError
Нет. Очередь на самом деле не unbouned, для неограниченного LinkedBlockingQueue, это capacity - это Integer.MAX_VALUE(2147483647). Когда недостаточно места, RejectedExecutionHandler будет обрабатывать новые задачи прибытия. И обработчик по умолчанию - AbortPolicy, он прерывает новые задачи напрямую.
I can't imagine a scenario when unbounded is better the bounded
Пользователи могут не заботиться о размере очереди или просто не хотят ограничивать кешированные задачи.
Если вам это небезразлично, вы можете создать ThreadPoolExecutor с помощью специального конструктора.
Спасибо, но я до сих пор не вижу допустимого и разумного варианта использования «неизвестной» очереди с ограничениями, которая может взорваться в любой момент, чего вы не ожидали .. Тем не менее, спасибо за ваш вклад
Поскольку вы спрашиваете о «сценарии использования», все очень просто: каждый раз, когда у вас есть много отдельных задач, которые вы хотите в конечном итоге завершить. Скажем, вы хотите загрузить сотни тысяч файлов? Создайте задачу загрузки для каждого, отправьте в ExecutorService, дождитесь завершения. В конечном итоге задачи будут завершены, поскольку вы больше не добавляете их, и нет причин для ограничения.
Это звучит как лучший ответ, но все же не решает проблему. Рано или поздно вы достигнете предела, и у вас не будет контроля над ним (потому что вы не предоставили свой собственный обработчик отклонения и т. д.). Мне кажется, это плохой дефолт от JDK ...
Да, именно это я имел в виду. Я считаю, что фабричные методы из
Executorsдолжны фактически использоватьArrayBlockingQueueи ожидать параметр, определяющий его длину. Таким образом, разработчикам будет более очевидно, что происходит за кулисами.