LinkedBlockingQueue vs ConcurrentLinkedQueue
мой вопрос относится к этому вопросу, заданному ранее. В ситуациях, когда я использую очередь для связи между потоками производителя и потребителя, люди обычно рекомендуют использовать LinkedBlockingQueue
или ConcurrentLinkedQueue
?
Какие преимущества / недостатки использования одного над другим?
основное отличие, которое я вижу с точки зрения API, заключается в том, что LinkedBlockingQueue
может быть дополнительно ограничен.
5 ответов:
для потока производителя / потребителя, я не уверен, что
ConcurrentLinkedQueue
Это даже разумный вариант - он не реализуетBlockingQueue
, который является основным интерфейсом для очереди производителя / потребителя IMO. Тебе придется позвонитьpoll()
подождите немного, если вы ничего не нашли, а потом снова опрос и т. д... это приводит к задержкам при появлении нового элемента и неэффективности, когда он пуст (из-за ненужного пробуждения от сна).из документов для BlockingQueue:
BlockingQueue
реализации предназначены для использования в основном для очередей производитель-потребительЯ знаю, что это не строго говорят, что только блокирующие очереди должны использоваться для очередей производителя-потребителя, но даже так...
этот вопрос заслуживает лучшего ответа.
Java
ConcurrentLinkedQueue
на алгоритм Магед М. Майкл и Майкл Л. Скотт на без блокировки блокировка-Free очереди."неблокирующий" как термин здесь для конкурирующего ресурса (наша очередь) означает, что независимо от того, что делает планировщик платформы, например, прерывание потока или если рассматриваемый поток просто слишком медленный, другие потоки, конкурирующие за тот же ресурс все равно смогу прогрессировать. Например, если задействована блокировка, поток, удерживающий блокировку, может быть прерван, и все потоки, ожидающие этой блокировки, будут заблокированы. Внутренние замки (тег
synchronized
ключевое слово) в Java также может иметь серьезное наказание за производительность-например, когда предвзятое замок участвует, и у вас есть конфликт, или после того, как VM решает "раздуть" блокировку после льготного периода спина и заблокировать конкурирующие потоки ... вот почему во многих контекстах (сценарии низкой / средней конкуренции), выполнение сравнения и наборов на атомарных ссылках может быть гораздо более эффективным, и это именно то, что делают многие неблокирующие структуры данных.Java
ConcurrentLinkedQueue
не только не блокирует, но и обладает удивительным свойством, что производитель не борется с потребителем. В сценарии с одним производителем / одним потребителем (SPSC) это действительно означает, что не будет никаких разногласий. В сценарии с несколькими производителями / одним потребителем потребитель не будет спорить с продюсерами. Эта очередь имеет конфликт, когда несколько производителей пытаютсяoffer()
, но это параллелизм, по определению. Это в основном общая цель и эффективная неблокирующая очередь.что касается того, что это не
BlockingQueue
, ну, блокирование потока для ожидания в очереди-это причудливо ужасный способ проектирования параллельных систем. Если вы не можете понять, как использоватьConcurrentLinkedQueue
в сценарии потребителя / производителя, а затем просто переключиться на более высокий уровень абстракции, как хороший актерский каркас.
LinkedBlockingQueue
блокирует потребителя или производителя, когда очередь пуста или полна, и соответствующий поток потребителя/производителя переводится в спящий режим. Но эта функция блокировки имеет стоимость: каждая операция put или take является блокировкой, оспариваемой между производителями или потребителями (если их много), поэтому в сценариях со многими производителями/потребителями операция может быть медленнее.
ConcurrentLinkedQueue
не использует блокировки, но CAS, на своих операциях put / take потенциально уменьшая конкуренцию с много потоков производителя и потребителя. Но будучи" ждать бесплатно " структура данных,ConcurrentLinkedQueue
не будет блокировать, когда пустой, это означает, что потребителю нужно будет иметь дело сtake()
возвращениеnull
значения по "занятому ожиданию", например, с потоком потребителя, поедающим процессор.Итак, какой из них" лучше " зависит от количества потребительских потоков, от скорости их потребления/производства и т. д. Для каждого сценария необходим эталон.
один конкретный случай использования, где
ConcurrentLinkedQueue
явно лучше, когда производители сначала производят что-то и заканчивают свою работу, помещая работу в очередь и только после потребители начинают потреблять, зная, что они будут сделаны, когда очередь пуста. (здесь нет параллелизма между производителем-потребителем, а только между производителем-производителем и потребителем-потребителем)