Java: ArrayBlockingQueue vs. LinkedBlockingQueue

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

Итак, мой вопрос: есть ли какая-либо промежуточная реализация BlockingQueue? Скажем, ArrayListBlockingQueue или BucketListBlockingQueue? Что-то вроде списка массивов, так что очередь может динамически увеличиваться в емкости, при этом все еще имея разумную выгоду от использования массива для хранения данных в конечном итоге?

Ответ 1

1. LinkedBlockingQueue (реализация LinkedList, но не реализация JDK LinkedList Использует статический внутренний класс Node для поддержания связей между элементами)

Constructor for LinkedBlockingQueue
public LinkedBlockingQueue(int capacity) 
{
        if (capacity < = 0) throw new IllegalArgumentException();
        this.capacity = capacity;
        last = head = new Node< E >(null);   // Maintains a underlying linkedlist. ( Use when size is not known )
}

Node класс, используемый для ведения ссылок

static class Node<E> {
    E item;
    Node<E> next;
    Node(E x) { item = x; }
}

2. ArrayBlockingQueue (реализация массива)

Конструктор для ArrayBlockingQueue

public ArrayBlockingQueue(int capacity, boolean fair) 
{
            if (capacity < = 0)
                throw new IllegalArgumentException();
            this.items = new Object[capacity]; // Maintains a underlying array
            lock = new ReentrantLock(fair);
            notEmpty = lock.newCondition();
            notFull =  lock.newCondition();
}

ИМХО Самая большая разница между ArrayBlockingQueue и LinkedBlockingQueue понятна из конструктора, у которого есть базовая структура данных Array и другие связанныеList.

ArrayBlockingQueue использует алгоритм двойного условия с одним замком, а LinkedBlockingQueue - это вариант алгоритма "две очереди блокировки" и имеет 2 условия блокировки 2 (takeLock, putLock)

До сих пор я дал сравнение между этими двумя реализациями. Возвращаясь к оригинальному вопросу. Аналогичный вопрос был задан в concurrency почтовый список в этом doug Lea рассказывает о DynamicArrayBlockingQueue, который является реализацией, предоставленной Давидом Курзинеком.

Ответ 2

Мои 2 цента:

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

Если вы пишете критически важную высокопроизводительную систему и используете очереди для передачи сообщений между потоками, вы всегда можете оценить размер очереди, необходимый для [Queue Size] = [Максимальная допустимая задержка] * [Максимальная скорость сообщения], Все, что может превысить такую ​​способность, означает, что вы страдаете от медленной потребительской проблемы. В критически важных приложениях такая задержка означает, что ваша система работает неправильно. Для обеспечения правильной работы системы может потребоваться какой-то ручной процесс.

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