Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/326.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java ArrayBlockingQueue:为什么中断异常块中存在信号条件?_Java_Multithreading - Fatal编程技术网

Java ArrayBlockingQueue:为什么中断异常块中存在信号条件?

Java ArrayBlockingQueue:为什么中断异常块中存在信号条件?,java,multithreading,Java,Multithreading,我一直在查看ArrayBlockingQueue的源代码。我试图理解为什么在捕捉中断异常时会发出条件信号。下面是一个示例,请注意在重新调用InterruptedException之前的notFull.signal()调用。为什么这是必要的?如果有两个线程同时调用offer,其中一个线程被中断,那么另一个线程是否会进入由锁保护的关键部分,然后看到count

我一直在查看
ArrayBlockingQueue
的源代码。我试图理解为什么在捕捉
中断异常
时会发出条件信号。下面是一个示例,请注意在重新调用
InterruptedException
之前的
notFull.signal()
调用。为什么这是必要的?如果有两个线程同时调用
offer
,其中一个线程被中断,那么另一个线程是否会进入由锁保护的关键部分,然后看到count
public boolean offer(E e, long timeout, TimeUnit unit)
    throws InterruptedException {

    if (e == null) throw new NullPointerException();
long nanos = unit.toNanos(timeout);
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        for (;;) {
            if (count != items.length) {
                insert(e);
                return true;
            }
            if (nanos <= 0)
                return false;
            try {
                nanos = notFull.awaitNanos(nanos);
            } catch (InterruptedException ie) {
                notFull.signal(); // propagate to non-interrupted thread
                throw ie;
            }
        }
    } finally {
        lock.unlock();
    }
}
public boolean提供(E、长超时、时间单位)
抛出中断异常{
如果(e==null)抛出新的NullPointerException();
long nanos=单位toNanos(超时);
最终重入锁定=this.lock;
lock.lockinterruptbly();
试一试{
对于(;;){
if(count!=items.length){
插入(e);
返回true;
}

如果(nano,则等待
wait
的线程完全有可能被信号中断,并且中断将优先。以下代码演示了这一点:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class SignalTest {
    public static void main(String... args) throws InterruptedException {
        for ( int i = 0; i < 2000; i++ ) {
            tryOnce();
        }
    }

    private static void tryOnce() throws InterruptedException {
        final Lock lock = new ReentrantLock();
        final Condition condition = lock.newCondition();

        Thread t = new Thread(new Runnable() {
            public void run() {

                try {
                    lock.lockInterruptibly();
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        });

        t.start();

        Thread.sleep(1);
        lock.lock();
        condition.signal();
        t.interrupt();
        lock.unlock();
    }
}
import java.util.concurrent.locks.Condition;
导入java.util.concurrent.locks.Lock;
导入java.util.concurrent.locks.ReentrantLock;
公共类信号测试{
公共静态void main(字符串…参数)抛出InterruptedException{
对于(int i=0;i<2000;i++){
tryOnce();
}
}
私有静态void tryOnce()引发InterruptedException{
最终锁定=新的可重入锁定();
最终条件=lock.newCondition();
线程t=新线程(新的可运行线程(){
公开募捐{
试一试{
lock.lockinterruptbly();
条件wait();
}捕捉(中断异常e){
e、 printStackTrace();
}最后{
lock.unlock();
}
}
});
t、 start();
睡眠(1);
lock.lock();
条件。信号();
t、 中断();
lock.unlock();
}
}
对我来说,2000次尝试中有2-10次会导致
中断异常
,即使我在中断之前发出信号,并从同一线程执行这两项操作

因为这是一种非常现实的可能性,如果catch块没有发出
信号
,它可能会导致一种永久等待状态,即使有空间可以添加新元素。因此,相反,条件会发出信号,如果有另一个等待线程,它会被唤醒

这是安全的,因为在被唤醒后,代码将始终确保它们被唤醒的条件(队列未满)实际上是真的(在这种情况下,
如果(count!=items.length)…
)。代码不会假设因为被唤醒,条件必须是真的

编辑 另外,为了帮助您理解,重要的是要注意for循环并不是严格意义上的互斥部分。如果两个线程同时调用offer,则第二个线程将等待第一个线程生成
锁,这是正确的,但您必须理解调用
notFull.await()
会释放锁(在
await()
返回后,锁将再次被拾取)。因此,您可以在
offer()
await()
调用中阻塞多个线程,而不是简单地在
lock interruptablely()
处阻塞

由于情况就是这样(同时发生多个阻塞
await()
s),如果被中断的线程以静默方式忽略了该信号,那么其他线程都不会被唤醒