我在“Add”和“Get”方法中有一个带有一些阻塞机制的队列,其中第一个线程添加数据,第二个线程获取数据。
public synchronized MyObj getData() {
synchronized (myLock) {
synchronized (this) {
if (isEmpty()) {
wait(0);
}
}
return getData();
}
}
public synchronized void addData(MyObj data) {
if (!isFull()) {
putData(data);
synchronized (this) {
notify();
}
}
}
在上面的代码中,如果第一个线程尝试获取数据并且队列为空,则通过wait(0)等待,直到其他线程添加数据以通过notify()等待释放等待释放。
现在我想在队列已满时添加另一个“锁定”,并且有人试图向其中添加更多数据:
public synchronized MyObj getData() {
synchronized (myLock) {
synchronized (this) {
if (isEmpty()) {
wait(0);
}
}
synchronized (this) {
notify();
}
return getData();
}
}
public synchronized void addData(MyObj data) {
synchronized (myLock) {
synchronized (this) {
if (isFull()) {
wait(0);
}
}
}
synchronized (this) {
notify();
}
PutData(data);
}
结果不是我所期望的,我想我得到一个死锁原因过程被卡住了。
更新
这是我获取数据的方式:
queueSize--;
startPointer = (startPointer + 1) % mqueueSize;
data = (String) queue[startPointer];
这是我添加数据的方式
queueSize++;
endPointer = (endPointer + 1) % mqueueSize;
queue[endPointer] = data;
public synchronized boolean isEmpty() {
return queueSize== 0;
}
public synchronized boolean isFull() {
return queueSize== mqueueSize;
}
答案 0 :(得分:3)
为什么你有三个synchronized
陈述? wait(0)
仅释放this
上的锁定,因此只需保留该锁定并转储方法中的synchronized
和synchronized(myLock)
。
每当你在某个对象上调用wait(在这种情况下你调用this
)时,该对象的锁定会自动释放,以允许其他线程继续。但是你永远不会在myLock
上等待(也不应该,因为你已经在呼叫this
)。那部分是多余的,导致死锁。
考虑这种情况:应该添加的线程获取myLock
上的锁,但发现队列已满,因此等待。此等待不会释放myLock
上的锁定。另一个线程想要获取数据但不能进入synchronized
块,因为第一个线程没有释放myLock
上的锁。
结论:删除synchronized(myLock)
块。
答案 1 :(得分:1)
为什么你不看java.util.BlockingQueue。可能它会对你的情况有用。
特别看一下java.util.LinkedBlockingQueue,如果你在构造函数中指定了队列的容量,那么队列就会阻塞。
答案 2 :(得分:1)
从方法签名中删除synchronized
关键字,因为这意味着您为整个方法调用保留this
监视器 - synchronized(this)
块只是多余的。
编辑:
...然后拨打等待并通知myLock
而不是this
。完全忘记this
上的同步。这是因为在等待(在当前代码中this
上)时,您没有释放myLock
锁定,因此其他线程无法转到notify()
。
答案 3 :(得分:0)
将if
替换为while
。如果收集真的变得不空/不满,那么仔细检查也不会有什么坏处。
你真的不需要两个锁。单锁几乎可以工作,应该更简单。
public synchronized T get()
{
while(isEmpty())
wait(0);
notifyAll();
return super.get();
}
public synchronized put(T t)
{
while(isFull())
wait(0);
super.put(t);
notifyAll();
}
当某些内容发生变化时,所有线程都会被唤醒。但如果他们无法完成工作,他们将wait
用于下一个notify
。
答案 4 :(得分:0)
如前所述,您的代码有太多synchronized
个注释。此外,在wait
条件中检查if
开启的条件,但理想情况下应在while
循环中检查以避免spurious wakeups。以下是修复这些内容的代码大纲。
// _isEmpty and _getData are private unsynchronized methods
public MyData get() throws InterruptedException {
// wait and notify should be called from a block
// synchronized on the same lock object (here myLock)
synchronized (myLock) {
// the condition should be tested in a while loop
// to avoid issues with spurious wakeups
while (_isEmpty()) {
// releases the lock and wait for a notify to be called
myLock.wait();
}
// when control reaches here, we know for sure that
// the queue is not empty
MyData data = _getData();
// try to wake up all waiting threads - maybe some thread
// is waiting for the queue not to be full
myLock.notifyAll();
}
}
// _isFull and _putData are private unsynchronized methods
public void put(MyData obj) throws InterruptedException {
synchronized (myLock) {
while (_isFull()) {
myLock.wait();
}
_putData(obj);
myLock.notifyAll();
}
}