为什么在LinkedBlockingQueue的put()中有一个while循环 [英] why is there a while loop in put() of LinkedBlockingQueue

查看:330
本文介绍了为什么在LinkedBlockingQueue的put()中有一个while循环的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  public void put(E e)抛出InterruptedException {
if(e == null)throw new NullPointerException();
int c = -1;
Node< E>节点=新的节点E(e);
最后的ReentrantLock putLock = this.putLock;
最终AtomicInteger计数= this.count;
putLock.lockInterruptible();
try {
while(count.get()== Capacity){
notFull.await();
}
入队(节点);
c = count.getAndIncrement();
如果(c + 1 <容量)
notFull.signal();
}最终{
putLock.unlock();
}
if(c == 0)
signalNotEmpty();
}

为什么会有while循环?



所有put线程都被putLock封闭。



当等待线程持有putLock时,没有线程可以增加'count'。

解决方案

有一个基本属性 await (适用于通过已同步,并同时使用 Object.wait ),您必须了解:



当调用 await 时,您正在释放锁条件与¹相关联。无法绕开它,否则,没有人可以获取锁,满足条件并对其调用 signal



当等待线程发信号时,它不会立即获得锁。那是不可能的,因为调用 signal 的线程仍然拥有它。相反,接收方将尝试重新获取锁,与调用 lockInterruptible()没什么不同。



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



因此,另一个线程到达了 put 可以在发出信号的线程之前获得锁,发现有空间,并且可以存储元素而不必担心信号。然后,到发出信号的线程获取锁时,该条件不再满足。因此,发出信号的线程永远不会仅仅依赖条件的有效性,因为它收到了信号,因此必须重新检查条件,如果不满足,则必须再次调用 await 。 / p>

这使在循环中检查条件成为使用 await 的标准习惯用法,如 条件界面,以及 Object.wait (仅出于完整性考虑)。换句话说,这甚至不是特定于API的。



由于必须对条件进行预检查和循环检查,因此规范甚至允许虚假唤醒,即线程从等待操作返回而实际上未接收到信号的事件。这可以简化某些平台的锁实现,而无需更改必须使用锁的方式。



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


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();
}

why is there a while loop?

All the putting thread is shut out by putLock.

No thread can increase 'count' when the waiting thread is holding the putLock.

解决方案

There is a fundamental property of await (which applies to the intrinsic locking via synchronized and using Object.wait as well), you have to understand:

When you invoke await, you are releasing the lock this Condition is associated with¹. There is no way around it, as otherwise, no-one could acquire the lock, make the condition fulfilled, and invoke signal on it.

When your waiting thread gets signaled, it does not get the lock back immediately. That would not be possible, as the thread which invoked signal still owns it. Instead, the receiver will try to re-acquire the lock, not much different to calling lockInterruptibly().

But this thread is not necessarily the only thread trying to acquire the lock. It doesn’t even have to be the first one. Another thread could have arrived at put before the signalling and waiting for the lock at lockInterruptibly(). So even if the lock was fair (which locks usually are not), the signaled thread had no precedence. Even if you gave signaled threads precedence, there could be multiple threads being signaled for different reasons.

So another thread arriving at put could get the lock before the signaled thread, find that there is space, and store the element without ever bothering with signals. Then, by the time the signaled thread acquired the lock, the condition is not fulfilled anymore. So a signaled thread can never rely on the validity of the condition just because it received a signal and therefore has to re-check the condition and invoke await again if not fulfilled.

This makes checking the condition in a loop the standard idiom of using await, as documented in the Condition interface, as well as Object.wait for the case of using the intrinsic monitor, just for completeness. In other words, this is not even specific to a particular API.

Since the condition has to be pre-checked and re-checked in a loop anyway, the specification even allows for spurious wakeups, the event of a thread returning from the wait operation without actually receiving a signal. This may simplify lock implementations of certain platforms, while not changing the way a lock has to be used.

¹ It’s important to emphasize that when holding multiple locks, only the lock associated with the condition is released.

这篇关于为什么在LinkedBlockingQueue的put()中有一个while循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆