简体   繁体   中英

Java LinkedBlockingQueue Realization

I looked at JDK LinkedBlockingQueue class and was lost.

public void put(E e) throws InterruptedException {
    if (e == null) throw new NullPointerException();
    // Note: convention in all put/take/etc is to preset local var
    // holding count negative to indicate failure unless set.
    int c = -1;
    final ReentrantLock putLock = this.putLock;
    final AtomicInteger count = this.count;
    putLock.lockInterruptibly();
    try {
        /*
         * Note that count is used in wait guard even though it is
         * not protected by lock. This works because count can
         * only decrease at this point (all other puts are shut
         * out by lock), and we (or some other waiting put) are
         * signalled if it ever changes from
         * capacity. Similarly for all other uses of count in
         * other wait guards.
         */
        while (count.get() == capacity) { 
                notFull.await();
        }
        enqueue(e);
        c = count.getAndIncrement();
        if (c + 1 < capacity)
            notFull.signal();
    } finally {
        putLock.unlock();
    }
    if (c == 0)
        signalNotEmpty();
}

Look please at the last condition (c == 0) , I think it should be (c != 0)

Thank you, I understand. But I have another one question about LinkedBlockingQueue realization. enqueue and dequeue function must not intersect. I see that when put() is executed, take() could be executed too. And head and tail objects have not synchronization, than enqueue and dequeue could work simultaneously in different thread. It is not thread-safe, failures could occur.

No, the intent is to signal only when the queue goes from 0 to 1 (ie the first time something is added to an empty queue). you don't need to "signal not empty" when adding items to a queue which already has items in it. (You'll notice that the notEmpty condition is only waited on when the queue count == 0).

You don't need to signal on every put. Ie, if the check was c != 0 then every time you put something you will be signaling that you aren't empty, but there is nobody to signal if you were not previously empty. So c == 0 ensures that you only signal when the queue changes from an empty state to a non empty state.

The comparison is c == 0, not c == 1, since the call to count is a "getAndIncrement" so 0 will be returned and then count will be incremented.

Edit: Apparently someone already got to this before me :\\

c is a count before increment:

c = count.getAndIncrement();

So, this condition means "if queue was empty, notify others that now it's not empty".

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM