Вопрос

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

Каковы преимущества / недостатки использования одного из них по сравнению с другим?

Основное отличие, которое я вижу с точки зрения API, заключается в том, что LinkedBlockingQueue может быть необязательно ограничен.

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

Решение

Для потока производителя / потребителя я не уверен, что ConcurrentLinkedQueue является даже разумным вариантом - он не реализует BlockingQueue , который является фундаментальным интерфейсом для очереди производителей / потребителей IMO. Вам нужно было бы вызвать poll () , немного подождать, если вы ничего не нашли, а затем повторить опрос и т. Д., Что приведет к задержкам при появлении нового элемента и неэффективности при его получении. пустой (из-за ненужного пробуждения от сна).

Из документов для BlockingQueue:

  Реализации

BlockingQueue предназначены для использования в основном для очередей производитель-потребитель

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

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

Этот вопрос заслуживает лучшего ответа.

Java- это ConcurrentLinkedQueue основан на знаменитом алгоритм Магеда М.Майкл и Майкл Л.Скотт для неблокирующий без блокировки очереди.

"Неблокирующий" как термин здесь для конкурирующего ресурса (нашей очереди) означает, что независимо от того, что делает планировщик платформы, например, прерывает поток, или если рассматриваемый поток просто слишком медленный, другие потоки, конкурирующие за тот же ресурс, все равно смогут работать.Например, если задействована блокировка, поток, удерживающий блокировку, может быть прерван, и все потоки, ожидающие этой блокировки, будут заблокированы.Внутренние блокировки (the synchronized ключевое слово) в Java также может привести к серьезному снижению производительности - например, когда смещенная блокировка задействован, и у вас действительно есть конфликт, или после того, как виртуальная машина решит "раздуть" блокировку после льготного периода вращения и заблокировать конкурирующие потоки...вот почему во многих контекстах (сценариях низкой / средней конкуренции) выполнение сравнения и наборов для атомарных ссылок может быть намного более эффективным, и это именно то, что делают многие неблокирующие структуры данных.

Java- это ConcurrentLinkedQueue не только не блокирует, но и обладает удивительным свойством, заключающимся в том, что производитель не конфликтует с потребителем.В сценарии с одним производителем / одним потребителем (SPSC) это действительно означает, что не будет никаких разногласий, о которых стоило бы говорить.В сценарии с несколькими производителями / одним потребителем потребитель не будет конфликтовать с производителями.В этой очереди действительно возникает конфликт, когда несколько производителей пытаются offer(), но это параллелизм по определению.По сути, это универсальная и эффективная неблокирующая очередь.

Что касается того, что это не было BlockingQueue, ну, блокировка потока для ожидания в очереди - это чертовски ужасный способ проектирования параллельных систем.Не надо.Если вы не можете понять, как использовать ConcurrentLinkedQueue в сценарии потребителя / производителя просто переключитесь на абстракции более высокого уровня, например, на хороший фреймворк actor.

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

ConcurrentLinkedQueue не использует блокировки, но CAS на операциях "положить / взять", потенциально уменьшающих конфликт со многими потоками производителей и потребителей. Но быть "жди бесплатно" структура данных, ConcurrentLinkedQueue не будет блокироваться, когда пуста, а это означает, что потребителю потребуется обработать take () , возвращая значения null с помощью " Ожидание занято " ;, например, когда потребительский поток потребляет процессор.

Итак, какой из них "лучше" зависит от количества потоков потребителей, от скорости, которую они потребляют / производят, и т. д. Для каждого сценария необходим эталон.

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

Другое решение (которое плохо масштабируется) - каналы рандеву: java.util.concurrent SynchronousQueue

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

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