Question

In ArrayBlockingQueue, inside the put method, why does it call notFull.signal() after catching InterruptedException? When the thread is going to terminate, why does it send out a 'not full' signal?

From the source:

public void put(E e) throws InterruptedException {
        if (e == null) throw new NullPointerException();
        final E[] items = this.items;
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            try {
                while (count == items.length)
                    notFull.await();
            } catch (InterruptedException ie) {
                notFull.signal(); // propagate to non-interrupted thread
                throw ie;
            }
            insert(e);
        } finally {
            lock.unlock();
        }
    }
Était-ce utile?

La solution

Imagine the following scenario:

  • Threads 1 and 4 are waiting on notFull, ie, the queue is full, and the lock is released.
  • Thread 2 holds the lock, and is about to remove an element from the queue.
  • Thread 3 interrupts Thread 1.

Now imagine the following interleaving:

+-+--+--------+-----------+------- TIME +---+------------+---------------------->
| |  |        |           |             |   |            |
+---------+   +------------------+      +----------+     |
| Thread2 |   |      Thread2     |      | Thread2  |     |
|  lock() |   | notFull.signal() |      | unlock() |     |
+---------+   +------------------+      +----------+     |
  |  |                    |                 |            |
  +---------------------+ |                 |            |
  |       Thread3       | |                 |            |
  | Thread1.interrupt() | |                 |            |
  +---------------------+ |                 |            |
     |                    |                 |            |
     +---------------+    +-------------+   +---------+  +----------------------+
     |   Thread1     |    |   Thread1   |   | Thread1 |  |       Thread1        |
     | interrupted() |    | signalled() |   |  lock() |  | InterruptedException |
     +---------------+    +-------------+   +---------+  +----------------------+

What if InterruptedException wasn't caught, and Thread 1 was just to unlock and abandon the wait? What would happen to Thread 4, who was still waiting for a signal on notFull? The signal had already been sent by Thread 2, but it just so happened that the receiving thread, Thread 1, had been interrupted, and the signal was wasted.

In short: If the thread received a signal when it was also interrupted, it passes along the signal to another thread, so that it isn't lost. This prevents threads from waiting indefinitely for something that already happened.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top