阻塞队列和线程访问顺序

6
我有一个情况,多个线程将通过调用take()轮询单个BlockingQueue。我想知道以下内容:
如果多个线程正在等待队列接收项目,他们是否会优先获取队列中的项目,以按照它们对take()的调用顺序进行,还是线程取出队列中的东西的顺序是任意的?
谢谢!
注意:过去我已经编写了自己的实现,但我想知道Java中的BlockingQueue实现是否可以为我完成这项工作。

1
一般来说,任何多线程应用程序都不应该对线程执行顺序做出任何假设。虽然有强制执行的方法,但 MT 应用程序的理念是不应该这样做。 - Dariusz
1
有趣的问题,我已经编写并运行了一个程序 - 没有固定的顺序。 - Tala
1
相关问题,其中还讨论了公平性。 - Josef Borkovec
3个回答

5
这取决于具体的实现方式。
如果使用 LinkedBlockingQueue,则 take() 方法会检查 ReentrantLock
public E take() throws InterruptedException {
    E x;
    int c = -1;
    final AtomicInteger count = this.count;
    final ReentrantLock takeLock = this.takeLock;
    takeLock.lockInterruptibly();
    ...
}

// declared as
private final ReentrantLock takeLock = new ReentrantLock(); // no fairness argument, defaults to false

javadoc 中说:

此类的构造函数接受一个可选的公平性参数。当设置为 true 时,在争用情况下,锁会优先授予访问等待时间最长的线程。 否则,此锁不保证任何特定的访问顺序。使用许多线程访问的公平锁的程序可能显示较低的总吞吐量(即更慢;通常要慢得多),但具有更小的获取锁的时间方差并保证没有饥饿现象。但是,请注意,锁的公平性不能保证线程调度的公平性。因此,使用公平锁的众多线程中的一个线程可能连续多次获取它,而其他活动线程则无法进展且当前未持有该锁。还要注意,未计时的 tryLock 方法不遵守公平性设置。如果锁可用,则尽管其他线程正在等待,它也会成功。


2
在许多情况下,javadocs会提到类是否是“公平”的,即阻塞分布得足够均匀,以便所有线程有相同的机会。但这并不一定意味着“以相同的顺序”进行。查看您特定队列实现的javadocs,以查看是否有关于公平性和/或顺序的信息。
至少`ArrayBlockingQueue`如下所示通报公平性:
该类支持等待生产者和消费者线程排序的可选公平策略。默认情况下,此排序不能保证。但是,使用fairness设置为true构建的队列按FIFO顺序授予线程访问权。公平性通常会降低吞吐量,但减少了变异性并避免饥饿。

1

这取决于实现方式,一个类是否支持可选的公平策略来对等待的生产者和消费者线程进行排序。例如,ArrayBlockingQueue可以是公平的,因为它有构造函数ArrayBlockingQueue(int capacity, boolean fair),但LinkedBlockingQueue不能。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接