假设我们创建了一个运行同步方法的线程.此方法尝试从空的阻塞队列中获取take().现在,让一个单独的线程在同一个对象上同步时尝试将put()和element放入阻塞队列.
这将导致死锁:
>在将元素添加到队列中之前,第一个线程不会释放锁定.
>第二个线程无法添加元素,直到释放锁以获取它为止.
如果这两个动作必须是原子的并在单独的线程上运行,那么如何在不导致死锁的情况下实现这一目标?
我知道take()和put()是线程安全的.我的问题是,何时将它们用作必须是原子的较大动作的一部分.
例:
import java.util.concurrent.*;
public class DeadlockTest {
String input = "Nothing added yet!";
LinkedBlockingQueue 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);
}
}
}
解决方法:
Say we create a thread which runs a synchronized method. This method tries to take() from an empty blocking queue.
听起来像是糟糕的设计.从同步方法或同步语句中调用任何阻塞方法通常是一个错误.
If the two actions need to be atomic and run on separate threads, how can this be achieved without causing a deadlock?
好吧,有两种可能性:
在一种情况下,两个线程作用于不同的数据.在那种情况下,他们应该使用不同的锁,并且它们根本不会互相干扰.
在另一种情况下,两个线程作用于相同的数据.在这种情况下,他们应该锁定相同的锁,而一个线程将不得不等待另一个.
也许您误解了阻塞队列的工作方式.如果一个线程正在等待从阻塞队列中获取take(),则不应阻止另一个线程调用put().那将与您想要的完全相反.
您想要的(以及从Java标准库中的任何阻塞队列实现中得到的)是,第二个线程中的put()操作将唤醒正在等待从队列中获取take()的线程.
标签:multithreading,java
来源: https://codeday.me/bug/20191119/2036664.html