Вообще говоря, скорость производственных задач больше, чем скорость потребления. Вопрос детализации - длина очереди и как соответствовать скорости производства и потребления.
Типичная модель производителя-потребителя выглядит следующим образом:
Для общего производства быстрее, чем потребление. Когда очередь заполнена, мы не хотим, чтобы какая -либо задача была проигнорирована или не выполнена. .. Продолжайте представлять задачи, когда очередь не заполнена, поэтому нет простального времени. Блокировка также легко.
Кроме того, когда очередь пуста, потребители не могут получить задачу, они могут подождать некоторое время, прежде чем получить его. .. Рекомендуется позвонить. Таким образом, когда производитель фактически прекратил производство, потребители не будут ждать бесконечно.
Следовательно, эффективная модель производства и потребления, поддерживающая блокирование.
Подождите, так как JUC помог нам внедрить пулы потоков, почему нам все еще нужно использовать этот набор вещей? Разве не удобнее использовать Executorservice напрямую?
Давайте посмотрим на основную структуру ThreadPoolexeCutor:
Но проблема заключается в том, что даже если вы вручную указываете блокировку в качестве реализации очереди при построении ThreadPoolexeCutor, на самом деле, когда очередь заполнена, метод выполнения не будет блокировать.
Кода -копия выглядит следующим образом:
public void execute (runnable command) {
if (command == null)
бросить новое NullPointerException ();
if (poolsize> = corepoolsize ||! addifundercorepoolsize (command)) {
if (runState == range && horamqueue.offer (command)) {
if (runstate! = Запуск || poolsize == 0)
обеспечить queedtaskhandled (команда);
}
else if (! addifundermaximumpoolsize (command))
отклонить (команда);
}
}
В настоящее время необходимо сделать что -то для достижения результата: когда производитель передает задачу, а очередь заполнена, производитель может заблокировать ее и дождаться использования задачи.
Ключ состоит в том, что в одновременной среде продюсер не может быть оценен в очередь, и ThreadPoolexeCutor.getQueue (). Size () не может быть вызван, чтобы определить, заполнена ли очередь.
При внедрении пула резьбов, когда очередь заполнена, DrecuceedExecutionHandler, принятый во время строительства, будет вызвана для отклонения обработки задачи. Реализация по умолчанию является прерванной, которая непосредственно выбрасывает DecuceedExecutionException.
Я не буду вдаваться в подробности о нескольких стратегиях отказа здесь. Потребление.
Кода -копия выглядит следующим образом:
Общественный статический класс callerrunspolicy реализует DecuceedExecutionHandler {
/**
* Создает <tt> callerrunspolicy </tt>.
*/
public callerrunspolicy () {}
/**
* Выполняет задание R в потоке вызывающего абонента, если только исполнитель
* был закрыт, и в этом случае задача отбрасывается.
* @param r Заполнимая задача, запрошенная для выполнения
* @param e Исполнитель, пытающийся выполнить эту задачу
*/
public void decuceedExecution (runnable r, threadpoolexecutor e) {
if (! e.isshutdown ()) {
r.run ();
}
}
}
Тем не менее, эта стратегия также имеет скрытые опасности, когда производители меньше, потребитель мог использовать все задачи в течение времени, когда производитель потребляет задачи, а очередь находится в пустом состоянии. Продолжайте производить задачи.
Ссылаясь на аналогичные идеи, самый простой способ, мы можем непосредственно определить DiecureedExecutionHandler и изменить его, чтобы назвать BlockingQueue.Put, когда очередь полна, чтобы реализовать блокировку производителя:
Кода -копия выглядит следующим образом:
new DecuceedExecutionHandler () {
@Override
public void decuceedExecution (runnable r, ThreadPoolexecutor Executor) {
if (! executor.isshutdown ()) {
пытаться {
executor.getQueue (). Put (r);
} catch (прерванная экспрессия e) {
// не следует прерывать
}
}
}
};
Таким образом, нам больше не нужно заботиться о логике очереди и потребителей.
По сравнению с исходным дизайном этот метод может уменьшить количество кода и может избежать многих проблем в одновременных средах. Конечно, вы также можете использовать другие средства, такие как использование семафоров в качестве пределов входа при отправке, но если вы просто хотите заблокировать производителя, это будет казаться сложным.