nolanar
nolanar

Reputation: 33

Deadlock caused by blocking methods

Say we create a thread which runs a synchronized method. This method tries to take() from an empty blocking queue. Now let a separate thread then try to put() and element onto the blocking queue while synchronized on the same object.

This causes a deadlock:

If the two actions need to be atomic and run on separate threads, how can this be achieved without causing a deadlock?

I understand that take() and put() are thread-safe. My question is for when they are used as part of larger actions that must be atomic.

Example:

import java.util.concurrent.*;

public class DeadlockTest {

    String input = "Nothing added yet!";
    LinkedBlockingQueue<String> buffer = new LinkedBlockingQueue<>();

    public synchronized String getFromBuffer() {
        System.out.println("Trying to get input from buffer.");
        try {
            input = buffer.take();
        } catch (InterruptedException ex) {}
        System.out.println("Got:" + input + "\n");
        return input;
    }

    public static void main(String[] args) throws InterruptedException {
        DeadlockTest dl = new DeadlockTest();

        new Thread(() -> {
            dl.getFromBuffer();
        }).start();

        // Give new thread time to run.
        Thread.sleep(500);

        synchronized (dl) {
            String message = "Hello, world!";

            System.out.println("Adding: " + message);
            dl.buffer.put(message);
            System.out.println("Added!\n");

            System.out.println("Message: " + dl.input);
        }
    }
}

Upvotes: 3

Views: 1277

Answers (1)

Solomon Slow
Solomon Slow

Reputation: 27124

Say we create a thread which runs a synchronized method. This method tries to take() from an empty blocking queue.

Sounds like bad design. It's usually a mistake to call any blocking methods from within a synchronized method or a synchronized statement.

If the two actions need to be atomic and run on separate threads, how can this be achieved without causing a deadlock?

Well, there's two possibilities:

In one case, the two threads are acting on different data. In that case, they should be using different locks, and they won't interfere with one another at all.

In the other case, the two threads are acting on the same data. In that case, they should lock the same lock, and one thread will have to wait for the other.


Maybe you misunderstand how a blocking queue works. If one thread is waiting to take() something from a blocking queue, that should never prevent another thread from calling put(). That would be the exact opposite of what you want.

What you want (and what you'll get from any of the blocking queue implementations in the Java standard library) is that the put() operation in the second thread will wake up the thread that's waiting to take() something from the queue.

Upvotes: 3

Related Questions