gpt4 book ai didi

java - 为什么 LinkedBlockingQueue 的 put() 中有一个 while 循环

转载 作者:行者123 更新时间:2023-11-29 08:24:07 32 4
gpt4 key购买 nike

public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
int c = -1;
Node<E> node = new Node<E>(e);
final ReentrantLock putLock = this.putLock;
final AtomicInteger count = this.count;
putLock.lockInterruptibly();
try {
while (count.get() == capacity) {
notFull.await();
}
enqueue(node);
c = count.getAndIncrement();
if (c + 1 < capacity)
notFull.signal();
} finally {
putLock.unlock();
}
if (c == 0)
signalNotEmpty();
}

为什么会有一个while循环?

putLock 关闭了所有的 putting 线程。

当等待线程持有 putLock 时,没有线程可以增加“计数”。

最佳答案

await 有一个基本属性(它适用于通过 synchronized 和使用 Object.wait 的内部锁定),您必须明白:

当您调用 await 时,您将释放锁Condition 与之相关联¹。没有办法绕过它,否则,没有人可以获取锁、满足条件并对其调用 signal

当您的等待线程收到信号时,它不会立即取回锁。这是不可能的,因为调用 signal 的线程仍然拥有它。相反,接收方将尝试重新获取锁,与调用 lockInterruptibly() 没有太大区别。

但是这个线程不一定是唯一一个尝试获取锁的线程。它甚至不必是第一个。在 lockInterruptibly() 发出信号并等待锁定之前,另一个线程可能已经到达 put。因此,即使锁是公平的(通常锁不是),发出信号的线程也没有优先权。即使您为已发出信号的线程赋予优先级,也可能有多个线程因不同原因而被发出信号。

因此到达 put 的另一个线程可以在发出信号的线程之前获得锁,发现有空间,然后存储元素而无需信号。然后,当信号线程获得锁时,条件不再满足。因此,一个有信号的线程永远不能仅仅因为它收到一个信号就依赖条件的有效性,因此必须重新检查条件并在不满足时再次调用 await

这使得在循环中检查条件成为使用 await 的标准用法,如 the Condition interface 中所述,以及 Object.wait对于使用内部监视器的情况,只是为了完整性。换句话说,这甚至不特定于特定的 API。

由于无论如何都必须在循环中预先检查和重新检查条件,规范甚至允许虚假唤醒,即线程从等待操作返回但实际上没有收到信号。这可能会简化某些平台的锁实现,同时不会改变必须使用锁的方式。

¹ 重要的是要强调,当持有多个锁时,只有与条件关联的锁被释放。

关于java - 为什么 LinkedBlockingQueue 的 put() 中有一个 while 循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54843122/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com