ArrayBlockingQueue использует одну блокировку для вставки и удаления, но LinkedBlockingQueue использует 2 отдельных блокировки


Я просматривал исходный код ArrayBlockingQueue и LinkedBlockingQueue. LinkedBlockingQueue имеет putLock и takeLock для вставки и удаления соответственно, но ArrayBlockingQueue использует только 1 блокировку. Я считаю, что LinkedBlockingQueue был реализован на основе дизайна, описанного в простой, быстрый и практичный неблокирующий и блокирующий Параллельные Алгоритмы Очередей . В этой статье они упоминают, что они держат фиктивный узел, так что очереди никогда не должны иметь доступ к head и dequeuers никогда не нужно обращаться к хвосту, который позволяет избежать тупиковых сценариев. Мне было интересно, почему ArrayBlockingQueue не заимствует ту же идею и не использует вместо нее 2 замка.

4 7

4 ответа:

ArrayBlockingQueue должен избегать перезаписи записей, чтобы знать, где находится начало и конец. LinkedBlockQueue не должен знать об этом, поскольку это позволяет GC беспокоиться об очистке узлов в очереди.

Мне было интересно, почему ArrayBlockingQueue не заимствует ту же идею и не использует вместо нее 2 замка.

Потому что ArrayBlockingQueue использует гораздо более простую структуру данных для хранения элементов очереди.

ArrayBlockingQueue хранит свои данные в одном массиве private final E[] items;. Для нескольких потоков, чтобы иметь дело с одним и тем же пространством хранения, либо при добавлении, либо при удалении из очереди, они должны использовать одну и ту же блокировку. Это происходит не только из-за барьера памяти, но и из-за защиты мьютексов, поскольку они изменяют одно и то же массив.

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

2 замка используются в LBQ для ограничения доступа к head и lock одновременно. Блокировка головы запрещает одновременное удаление двух элементов, а блокировка хвоста запрещает одновременное добавление двух элементов в очередь. два замка вместе предотвращают гонки.

Я думаю, что ABQ может заимствовать ту же идею, что и LBQ. Пожалуйста, обратитесь к моему коду http://pastebin.com/ZD1uFy7S и аналогичный вопрос я задал на SO ArrayBlockingQueue: concurrent put and take.

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

Для получения дополнительной информации, пожалуйста, взгляните на http://jsr166-concurrency.10961.n7.nabble.com/ArrayBlockingQueue-concurrent-put-and-take-tc1306.html .