Где вы должны использовать реализации BlockingQueue вместо простых реализаций очереди?

Я думаю, что я перефразирую свой вопрос от

Где вы должны использовать реализации BlockingQueue вместо простых реализаций очереди?

в

Каковы преимущества / недостатки BlockingQueue по сравнению с реализациями Queue, принимая во внимание такие аспекты, как скорость, параллелизм или другие свойства, которые варьируются, например, время доступа к последнему элементу.

Я использовал оба вида очередей. Я знаю, что очередь блокировки обычно используется в параллельном приложении. Я писал простой пул ByteBuffer, в котором мне нужно было заполнить объекты ByteBuffer. Мне нужна была самая быстрая, многопоточная реализация очереди. Даже есть реализации List, такие как ArrayList, который имеет постоянное время доступа к элементам.

Кто-нибудь может обсудить плюсы и минусы реализации BlockingQueue против Queue против List?

В настоящее время я использовал ArrayList для хранения этих объектов ByteBuffer.

Какую структуру данных я буду использовать для хранения этих объектов?

11.12.2008 04:35:46
4 ОТВЕТА
РЕШЕНИЕ

Ограниченная емкость BlockingQueueтакже полезна, если вы хотите ограничить какой-либо запрос. С неограниченной очередью производители могут значительно опередить потребителей. Задачи в конечном итоге будут выполнены (если только их не будет так много OutOfMemoryError), но продюсер может уже давно сдаться, поэтому усилия будут потрачены впустую.

В подобных ситуациях может быть лучше сообщить потенциальному производителю, что очередь заполнена, и быстро сдаться в случае сбоя. Например, источником может быть веб-запрос с пользователем, который не хочет ждать слишком долго, и хотя он не будет потреблять много циклов ЦП во время ожидания, он использует ограниченные ресурсы, такие как сокет и некоторое количество памяти. , Отказ предоставит поставленным в очередь задачам лучший шанс для своевременного завершения.


Что касается измененного вопроса, который я интерпретирую как «Что такое хорошая коллекция для хранения объектов в пуле?»

Неограниченный LinkedBlockingQueueявляется хорошим выбором для многих бассейнов. Однако, в зависимости от вашей стратегии управления пулом, ConcurrentLinkedQueueтоже может работать.

В приложении для пула блокирующий «пут» не подходит. Управление максимальным размером очереди является задачей менеджера пула - он решает, когда создавать или уничтожать ресурсы для пула. Клиенты пула занимают и возвращают ресурсы из пула. Добавление нового объекта или возврат ранее заимствованного объекта в пул должны быть быстрыми, неблокирующими операциями. Таким образом, очередь с ограниченной емкостью не является хорошим выбором для пулов.

С другой стороны, при извлечении объекта из пула большинство приложений хотят подождать, пока ресурс не станет доступен. Операция «take», которая блокирует, по крайней мере временно, гораздо более эффективна, чем «операция ожидания ожидания» - повторный опрос, пока ресурс не станет доступным. Это LinkedBlockingQueueхороший выбор в этом случае. Заемщик может заблокировать на неопределенный срок takeили ограничить время, которое он хочет заблокировать poll.

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

Обе эти коллекции дают хорошую производительность и простоту использования в параллельном приложении. Для непараллельных приложений ArrayListсложно победить. Даже для динамически растущих коллекций накладные расходы на элемент LinkedListпозволяют a ArrayListс некоторыми пустыми слотами оставаться конкурентоспособными в отношении памяти.

35
11.12.2008 16:48:17
Спасибо Эриксону за такое хорошее объяснение. Это решило мою проблему.
Vaibhav Kamble 12.12.2008 09:27:10

Вы бы увидели BlockingQueueв многопоточных ситуациях. Например, вам нужно передать в качестве BlockingQueueпараметра для создания, ThreadPoolExecutorесли вы хотите создать его с помощью конструктора. В зависимости от типа очереди, которую вы передаете исполнителю, может действовать по-разному.

4
11.12.2008 04:40:50

BlockingQueue также полезно для сериализации параллельных операций, которые зависят друг от друга.

Чтобы привести конкретный (хотя и несколько произвольный) пример, вот параллельный тест для веб-приложения с очередью пациентов в режиме реального времени, который callInPatient()должен запускаться параллельно registerPatientToAppointment(), но должен дождаться registerPatientToAppointment()завершения до выполнения callPatientInAtDoctorsOffice():

public class ClinicPatientQueueAppTest extends ParallelTest {

    private static final BlockingQueue WAIT_FOR_REGISTRATION_QUEUE = new ArrayBlockingQueue(2);

    @Test
    public void callInPatient() {
        loginToDoctorsOffice("user", "password");
        waitUntilRegistrationCompleted();  // <--
        callPatientInAtDoctorsOffice();
    }

    @Test
    public void registerPatientToAppointment() {
        registerPatientAtRegistrationKiosk("Patient Peter");
        notifyRegistrationCompleted(); // <--
    }

    private void waitUntilRegistrationCompleted() {
        WAIT_FOR_REGISTRATION_QUEUE.take();
    }

    private void notifyRegistrationCompleted() {
        WAIT_FOR_REGISTRATION_QUEUE.put(this);
    }

}
0
19.04.2017 11:43:37

Это Queueреализация, которая дополнительно поддерживает операции, которые

дождаться, пока очередь не станет пустой при получении элемента,

а также

подождите, пока место станет доступным в очереди при сохранении элемента.

Если вам требуется вышеуказанная функциональность, за которой последует ваша Queueреализация, используйтеBlocking Queue

3
21.08.2017 07:00:53