Итак, копаясь в недрах исходного кода 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()
.