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:
- The first thread will not release the lock until an element is added to the queue.
- The second thread cannot add an element until the lock is free for it to acquire.
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);
}
}
}