2010-07-26 44 views
6

我有3个主题:2个消费者,ConsumerAConsumerB,以及ProducerJava:LinkedBlockingQueue是否考虑到消费者的订单?

我也有一个LinkedBlockingQueue queue

在t = 1:ConsumerA呼叫queue.take()

在t = 2:Consumer B调用queue.take()

在t = 3 :Producer调用queue.put(foo)

是否保证ConsumerA在ConsumerB之前接收到foo?换句话说,消费者调用take()的顺序是通知每个消费者的顺序?

如果没有,是否有一个替代的数据结构会根据订单给予更高的优先级?

回答

3

从源代码看,它不能保证。根据调度程序的感觉,随机唤醒一个线程有一个防护块机制。

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

全码:http://kickjava.com/src/java/util/concurrent/LinkedBlockingQueue.java.htm

编辑:刚刚又看了看ReenterantLock和条件,该线程在FIFO顺序信号,显然。所以,第一个等待插入的线程将首先被发信号。但是,这些是实现细节!不要依赖他们。

的实现不需要 定义相同的保证或 语义所有三种形式的 等待,也不支持 中断线程的实际挂起 它需要

3

在很多情况下,进入队列的线程顺序将以适当的顺序排列。但是,LinkedBlocking队列使用不公平的锁定。这样做可以让线程互相驳接。虽然很少发生以下情况。

  • 线程A进入并轮询。
  • 线程B进入尝试轮询 - 线程A持有锁和公园螺纹B.
  • 线程A饰面和信号乙
  • 线程C进入和B在已启动的完全
  • 线程B的尝试之前获得锁轮询 - 线程C持有锁和公园线程B.

这是一种可能性。

1

所以通过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一个实例,其实现由接口java.util.concurrent.locks.Condiion所述的正常同步变量调用await()signal()signalAll()和方法。


寻找在用于ConditionObject类的源代码,它使两个构件称为firstWaiterlastWaiter是在CLH锁定队列中第一个和最后节点(的java.util.concurrent.locks.AbstractQueuedSynchronizer$Node实例)。

在该类状态的文档:

线程可能会尝试收购,如果它是第一个在队列中。但首先并不能保证成功;它只会给予抗争的权利。所以当前发布的竞争者线程可能需要重新等待。

所以我相信这里的答案是,在LinkedBlockingQueue企图take()方法优待那些所谓take()较早线程。它会给第一个线程呼叫take()第一次获取队列项目的机会,但是由于超时,中断等原因不能保证成为第一个从项目中获取项目的线程队列。

请记住,这是完全特定于此特定实施。一般来说,假设在take()的调用将唤醒一个随机等待线程,当一个队列项目变得可用时,不一定是第一个调用take()的线程。