Ограниченная BlockingQueue, которая не блокирует

StackOverflow https://stackoverflow.com/questions/1231378

  •  22-07-2019
  •  | 
  •  

Вопрос

Название этого вопроса заставляет меня сомневаться, существует ли оно, но все же:

Меня интересует, есть ли в Java реализованный BlockingQueue , который ограничен по размеру и никогда не блокируется, а выдает исключение при попытке поставить в очередь слишком много элементов.

Изменить . Я передаю BlockingQueue исполнителю, который, как я полагаю, использует метод add (), а не offer (). Можно написать BlockingQueue, который обернет другой BlockingQueue и делегировать вызовы add () для offer ().

Это было полезно?

Решение

Изменить. Исходя из вашего нового описания, я считаю, что вы задаете не тот вопрос. Если вы используете Executor, вы, вероятно, должны определить пользовательский RejectedExecutionHandler вместо изменения очереди. Это работает только в том случае, если вы используете ThreadPoolExecutor, но если это не так, вероятно, было бы лучше изменить Executor, а не очередь.

Я считаю, что было бы ошибкой переопределять предложение и заставлять его вести себя как add. Интерфейсные методы составляют контракт. Код клиента, который использует блокирующие очереди, зависит от методов, которые фактически выполняют то, что указано в документации. Нарушение этого правила открывает мир боли. Это, и это не элегантно.

<Ч>

добавить () метод в BlockingQueues делает это, но у них также есть offer () , который обычно является лучшим выбором. Из документации на предложение ():

  

Вставляет указанный элемент в   хвост этой очереди, если это возможно   сделать это немедленно, не превышая   емкость очереди, возвращая истину   в случае успеха и ложь, если эта очередь   полный. Этот метод обычно   предпочтительнее метода add (E), который может   не удается вставить элемент только   бросить исключение.

Это работает для всех таких очередей независимо от конкретной реализации (ArrayBlockingQueue, LinkedBlockingQueue и т. д.)

BlockingQueue<String> q = new LinkedBlockingQueue<String>(2);
System.out.println(q.offer("foo")); // true
System.out.println(q.offer("bar")); // true
System.out.println(q.offer("baz")); // false

Другие советы

  

Можно написать BlockingQueue, который   оборачивает другой BlockingQueue и   делегирует вызовы add () в offer ().

Если предполагается, что это вопрос ... ответ - "Да", но вы можете сделать это более аккуратно, создав подкласс, который переопределяет add (). Единственный улов (в обоих случаях) заключается в том, что ваша версия add не может генерировать какие-либо проверенные исключения, которые отсутствуют в методе, который вы переопределяете, поэтому ваш " заблокирует " исключение нужно будет снять.

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

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) {
            if (runState == RUNNING && workQueue.***offer***(command)) {
                if (runState != RUNNING || poolSize == 0)
                    ensureQueuedTaskHandled(command);
            }
            else if (!addIfUnderMaximumPoolSize(command))
                reject(command); // is shutdown or saturated
        }
    }

В простом сценарии использования для получения запросов, выполняемых из исходной базы данных в пакетном режиме (executor), обогащения в пакетном режиме и помещения в другую базу данных (executor), вы захотите выполнять запросы только с той скоростью, с которой они помещаются в другую базу данных. В этом случае исполнитель dest должен принять ограниченного блокировочным исполнителем для решения проблемы, чем продолжать опрос и проверку того, сколько было выполнено для выполнения большего количества запросов.

Ой, смотрите мой оставшийся комментарий:

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top