当前位置: 首页 > 面试题库 >

为什么java.util.concurrent.ArrayBlockingQueue为什么在调用await()时使用“ while”循环而不是“ if”循环?

谯振国
2023-03-14
问题内容

我一直在使用“
if”来测试自己的版本,并且一切似乎都正常。当然,如果使用signalAll()而不是signal(),这将导致严重崩溃,但是如果一次仅通知一个线程,这怎么会出错?

他们的代码在这里
-检查put()和take()方法;在Condition的JavaDoc顶部可以看到一个更简单,更重点的实现。

下面是我实施的相关部分。

public Object get() {
    lock.lock();
    try {
        if( items.size() < 1 )
            hasItems.await();
        Object poppedValue = items.getLast();
        items.removeLast();
        hasSpace.signal();
        return poppedValue; 
    } catch (InterruptedException e) {
        e.printStackTrace();
        return null;
    } finally {
        lock.unlock();
    }
}

public void put(Object item) {
    lock.lock();
    try {
        if( items.size() >= capacity )
            hasSpace.await();
        items.addFirst(item);
        hasItems.signal();
        return;
    } catch (InterruptedException e) {
        e.printStackTrace();
    } finally {
        lock.unlock();
    }
}

PS我知道,通常,尤其是在这样的lib类中,应该让异常渗入。


问题答案:

防止虚假唤醒。JVM并不能保证线程将再次开始运行的唯一可能原因是因为您按预期的方式调用了signal。有时,它会只是偶然地开始而已(虚假唤醒)。因此,如果要运行的条件实际上不是真的,则必须再次等待。

这在javadoc中对wait方法进行了解释:http
:
//java.sun.com/javase/6/docs/api/java/lang/Object.html#wait%28long%29

并在文档中提及等待:http
:
//java.sun.com/javase/6/docs/api/java/util/concurrent/locks/Condition.html#await%28%29

与此条件相关联的锁被原子释放,并且出于线程调度的目的,当前线程被禁用,并且处于休眠状态,直到发生以下四种情况之一:

  • 其他一些线程为此条件调用signal()方法,并且当前线程恰好被选择为要唤醒的线程;要么

  • 其他一些线程为此条件调用signalAll()方法。要么

  • 其他一些线程中断当前线程,并支持中断线程挂起;要么

*发生“虚假唤醒”。

Condition接口的某些实现可能会抑制虚假唤醒,但是依赖该实现将因此依赖于实现细节,并使您的代码不可移植



 类似资料:
  • 所以我这里有一个程序,它只是简单地模仿跳棋(但不是跳,而是一个棋子简单地“吃掉”另一个棋子)。我有一个简单的类,它实现了一个“checkers”类对象,并创建了一个名为“chips”的int数组变量。还有一个“while”语句,它在chip[0]和chips[1]整数大于0时创建了一个循环。看起来是这样的: Checkers类中的count方法如下所示: 板是8 x 8(这就是board.leng

  • 我正在写一份简单的银行申请书。在我的程序中,我使用了while循环。如果用户输入错误,它将再次提示用户输入。 现在的问题是我无法编写任何语句。它总是显示错误(比如:unreachable语句),最终该行不会被打印出来。 我该怎么解决这个问题? [我之所以需要使用,是因为我想打印用户输入的所有信息。] 我正在从事的项目:

  • 问题内容: 我读过,我们应该始终在循环内调用a : 它可以正常工作而没有循环,那为什么呢? 问题答案: 你不仅需要循环它,还需要在循环中检查条件。Java不能保证仅通过notify()/ notifyAll()调用或正确的notify()/ notifyAll()调用来唤醒你的线程。由于此属性,无环版本可能在你的开发环境上工作,而在生产环境上意外失败。 例如,你正在等待一些东西: 邪恶的线程出现了

  • 问题内容: 我也在学习Java和android。我们可以在while循环中执行的几乎所有事情都可以在while循环中执行。 我发现一个简单的条件,使用while循环比for循环更好 如果我必须在程序中使用counter的值,那么我认为while循环要比for循环好 使用while循环 在这种情况下,我发现while循环要比for循环好,因为如果要在for循环中实现相同的效果,则必须将counter

  • 问题内容: 以下示例在Node.js书中给出: 解释了while循环为何阻止执行时,作者说: 节点将永远不会执行超时回调,因为事件循环卡在了循环中,而循环在第7行开始了,因此永远不会给它处理超时事件的机会! 但是,作者没有解释为什么这是在事件循环的背景下发生的,还是在幕后真正发生了什么。 有人可以详细说明吗?为什么节点卡住?以及如何在保留控制结构的同时更改上述代码,以使事件循环不会被阻塞,并且代码

  • 在我的程序中,我发现当为时,循环无法正确退出。它看起来像整数溢出,远远大于10,循环不会停止。请告诉我发生了什么,以及如何在大型项目中避免这个错误。 代码链接