Java: LinkedBlockingQueue принимает во внимание порядок потребителей?

У меня есть 3 потока: 2 потребителя, ConsumerA и ConsumerB, и a Producer.

У меня также есть a LinkedBlockingQueue queue

В t=1: ConsumerA вызовы queue.take ()

В t=2: ConsumerB называет queue.take ()

В t=3: Producer вызовы queue.put (нечто)

Гарантируется, что ConsumerA получает нечто перед ConsumerB? Другими словами, порядок, в котором потребители вызывает take() порядок, в котором каждый уведомляется?

В противном случае существует ли альтернативная структура данных, которая отдаст более высокий приоритет на основе порядка?

7
задан zer0stimulus 26 July 2010 в 22:27
поделиться

3 ответа

Судя по исходному коду, это не гарантируется. Имеется механизм защищенного блока с случайным пробуждением одного потока, в зависимости от того, как себя чувствует планировщик.

 notEmpty.signal(); // propagate to a non-interrupted thread

Полный код: http://kickjava.com/src/java/util/concurrent/LinkedBlockingQueue.java.htm

Изменить: только что снова взглянул на ReenterantLock и Condition, потоки сигнализируются в порядке FIFO , видимо. Таким образом, первый поток, ожидающий вставки, будет сигнализирован первым. Однако это детали реализации! Не надейтесь на них.

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

3
ответ дан 7 December 2019 в 07:39
поделиться

Во многих случаях порядок потоков, поступающих в очередь, будет в соответствующем порядке. Однако очередь LinkedBlocking использует несправедливую блокировку. Это позволяет потокам вмешиваться друг в друга. Хотя в редких случаях может случиться следующее.

  • Тема A входит и опрашивает.
  • Поток B входит и пытается выполнить опрос - поток A удерживает блокировку и паркует поток B.
  • Поток A завершает работу и сигнализирует B
  • Поток C входит и получает блокировку до того, как поток B полностью не припаркован
  • Поток B пытается to poll - Thread C удерживает блокировку и останавливает поток B.

Это одна из возможностей.

3
ответ дан 7 December 2019 в 07:39
поделиться

Итак, копаемся в недрах исходного кода Java 6 (пропустите часть между горизонтальными правилами, если вас не волнует фактический код, ответственный за этот материал)


Класс java.util.concurrent.LinkedBlockingQueue реализует мьютекс, используя экземпляры java.util.concurrent.locks.ReentrantLock.

В свою очередь, переменные синхронизации создаются с использованием java.util.concurrent.locks.ReentrantLock.newCondition () , который вызывает java.util.concurrent.locks.ReentrantLock $ Sync.newCondition () .

Метод java.util.concurrent.locks.ReentrantLock $ Sync.newCondition () возвращает экземпляр java.util.concurrent.AbstractQueuedSynchronizer $ ConditionObject , который реализует обычную синхронизацию вызовы переменных к await () , signal () и signalAll () , описываемым интерфейсом java.util.concurrent.locks.Condiion .


Глядя на исходный код класса ConditionObject , он сохраняет два члена с именами firstWaiter и lastWaiter , которые являются первым и последним узлами в блокировке CLH. очередь (экземпляры java.util.concurrent.locks.AbstractQueuedSynchronizer $ Node ).

В документации этого класса говорится:

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

Я считаю, что ответ здесь заключается в том, что метод take () в LinkedBlockingQueue пытается предоставить предпочтение тем потокам, которые ранее вызывали take () . Это даст первому потоку для вызова take () первый шанс захватить элемент очереди, когда он станет доступным, но из-за тайм-аутов, прерываний и т. Д. Этот поток не гарантируется быть первым потоком, который получит элемент из очереди.

Имейте в виду, что это полностью зависит от конкретной реализации. В общем, вы должны предполагать, что вызовы take () разбудят случайный ожидающий поток, когда становится доступным элемент очереди, и не обязательно первый, который вызвал take () .

1
ответ дан 7 December 2019 в 07:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: