假设我们创建了一个运行同步方法的线程。此方法从空阻塞队列尝试take()
。现在让一个单独的线程在同一个对象上同步时尝试put()
和元素到阻塞队列。
这导致死锁:
如果这两个动作需要是原子的并且在不同的线程上运行,那么如何在不造成死锁的情况下实现呢?
我了解take()
和put()
是线程安全的。我的问题是当它们被用作必须是原子的大型行动的一部分时。
示例:
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);
}
}
}
答案 0 :(得分:3)
假设我们创建了一个运行同步方法的线程。此方法尝试从空的阻塞队列中获取()。
听起来很糟糕的设计。从synchronized
方法或synchronized
语句中调用任何阻止方法通常是错误的。
如果这两个动作需要是原子的并且在不同的线程上运行,那么如何在不造成死锁的情况下实现呢?
嗯,有两种可能性:
在一种情况下,两个线程对不同的数据起作用。在这种情况下,他们应该使用不同的锁,他们根本不会互相干扰。
在另一种情况下,两个线程作用于相同的数据。在这种情况下,他们应该锁定相同的锁,并且一个线程将不得不等待另一个。
也许您误解了阻塞队列的工作原理。如果一个线程正在等待来自阻塞队列的take()
某个东西,那绝不应该阻止另一个线程调用put()
。这与你想要的完全相反。
您想要的(以及您从Java标准库中的任何阻塞队列实现中获得的内容)是第二个线程中的put()
操作将唤醒“#{1}}操作。等待队列中take()
的东西。