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

问题描述

我一直在玩我自己的版本,使用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?

他们的代码这里 - 查看放置() 和 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.

推荐答案

防止虚假唤醒.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 中对 wait 方法进行了解释: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

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

  • 其他一些线程为此 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

其他一些线程为此条件调用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

* 发生虚假唤醒".

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 在调用 await() 时使用“while"循环而不是“if"?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-18 06:50