0

The common implementation is here, Java's built-in implementation is here. I have two questions regarding these two implementations:

1) The first implementation use synchronized key word on put() and take() methods, which means only one thread can access one method. Let's say if thread A call put() and found the queue is full, so it's waiting, then no one can ever call take() method since the lock is not released yet, how can the implementation be used?

2) Java's built-in uses two locks: takeLock and putLock, and used in put() and take() respectively. I saw that the interval queue is a linked list, which is not thread-safe, how can that be done?

3
  • 1
    for 1: Waiting releases the lock, so it doesn't block other threads from taking. Commented Apr 9, 2015 at 15:15
  • 3
    Your assumption in #1 is wrong: Invoking wait() actually releases the lock for that thread. Another thread can then capture the lock in the take() method, and the thread stuck in put() will be awakened when notifyAll() is called by a different thread. Commented Apr 9, 2015 at 15:15
  • @PlatinumAzure Thanks, any idea for the second one? Commented Apr 9, 2015 at 16:10

1 Answer 1

1

As already mentioned in some of the comments the first implementation just uses traditional wait()/notify() mechanism where one thread waits (and of course releasing lock) for being notified by other threads.

The second one uses different locks each for put and take operations. So the individual operations (simultaneous put() or take()) are synchronous. But they need to communicate with each other when queue is full or empty. So they interact with each other through condition. Checkout the two private methods-

    /**
     * Signals a waiting take. Called only from put/offer (which do not
     * otherwise ordinarily lock takeLock.)
     */
    private void signalNotEmpty() {
        final ReentrantLock takeLock = this.takeLock;
        takeLock.lock();
        try {
            notEmpty.signal();
        } finally {
            takeLock.unlock();
        }
    }

    /**
     * Signals a waiting put. Called only from take/poll.
     */
    private void signalNotFull() {
        final ReentrantLock putLock = this.putLock;
        putLock.lock();
        try {
            notFull.signal();
        } finally {
            putLock.unlock();
        }
    }

put method signals other threads trying to take/poll from empty queue and take method signals other threads trying to put elements into full queue.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, I was trying to understand how do two locks guarantee thread-safety, double check the code, found put/take operations are performed on two nodes (head/tail respectively), which explains everything.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.