为什么java.util.concurrent.ArrayBlockingQueue使用'while'循环而不是'if'调用await()? [英] Why does java.util.concurrent.ArrayBlockingQueue use 'while' loops instead of 'if' around calls to await()?

查看:409
本文介绍了为什么java.util.concurrent.ArrayBlockingQueue使用'while'循环而不是'if'调用await()?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在玩我自己的版本,使用'if',似乎都工作正常。当然,如果使用signalAll()而不是signal(),但是如果一次只有一个线程被通知,那么这将会崩溃。

I have been playing with my own version of this, using 'if', and all seems to be working fine. Of course this will break down horribly if signalAll() is used instead of signal(), but if only one thread at a time is notified, how can this go wrong?

他们的代码此处 - 查看put( )和take()方法;在 JavaDoc for Condition

Their code here - check out the put() and take() methods; a simpler and more-to-the-point implementation can be seen at the top of the JavaDoc for Condition.

我的实现的相关部分如下。

Relevant portion of my implementation below.

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

我知道一般来说,特别是在这样的lib类中,应该让异常溢出。

P.S. I know that generally, particularly in lib classes like this, one should let the exceptions percolate up.

推荐答案

UPS。 JVM不能保证线程将再次运行的唯一可能的原因是因为你以你想要的方式调用信号。有时它只是不小心开始走了(虚假的苏醒)。所以你必须继续等待,如果你想运行的条件不是真的。

To protect against spurious wake ups. There is no guarantee made to you by the JVM that the only possible reason the thread will ever start running again is because you called signal in the way you intended. Sometimes it will just get started accidentally and go (Spurious wake up). So you have to keep waiting again if the condition you want to run on isn't actually true.

这是在等待方法的javadoc中解释的:
http://java.sun.com/javase/6/docs/api/java/lang/Object.html# wait%28long%29

This is explained in the javadoc for the wait method: http://java.sun.com/javase/6/docs/api/java/lang/Object.html#wait%28long%29

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

And mentioned in the docs for await: http://java.sun.com/javase/6/docs/api/java/util/concurrent/locks/Condition.html#await%28%29



条件被原子释放,
当前线程禁用
用于线程调度目的,
休眠,直到
发生的四件事之一:

The lock associated with this Condition is atomically released and the current thread becomes disabled for thread scheduling purposes and lies dormant until one of four things happens:


  • 某些其他线程调用此Condition的signal()方法,
    当前线程恰好是
    选择为线程被唤醒;

  • Some other thread invokes the signal() method for this Condition and the current thread happens to be chosen as the thread to be awakened; or

一些其他线程调用此Condition的signalAll()

Some other thread invokes the signalAll() method for this Condition; or

一些其他线程中断当前线程,并且支持
线程挂起中断;或

Some other thread interrupts the current thread, and interruption of thread suspension is supported; or

*发生虚假唤醒。 b

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

Some implementations of the Condition interface may suppress spurious wakeups, but relying on that would hence be relying on an implementation detail and makes your code unportable.

这篇关于为什么java.util.concurrent.ArrayBlockingQueue使用'while'循环而不是'if'调用await()?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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