【发布时间】:2016-01-31 20:59:13
【问题描述】:
假设我们创建了一个运行同步方法的线程。这个方法尝试从一个空的阻塞队列中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);
}
}
}
【问题讨论】:
-
嗯,是的,所以即使队列为空,take/pop/whatever 也必须释放锁。
-
通常,你使用额外的线程来执行阻塞的东西,然后使用一些事件循环读取结果。
-
@MartinJames
take()和put()获取和释放的锁对象与同步方法使用的锁对象不同。我无权访问阻塞队列内部的锁。如果我这样做了,我可以将它用作同步块的参数,而不是使方法同步。
标签: java multithreading