[英]Wait/Notify dead lock
I have a queue with some blocking mechanism in "Add" and "Get" methods, where first thread adds data and second thread gets data. 我在“添加”和“获取”方法中有一个带有某种阻止机制的队列,其中第一个线程添加数据,第二个线程获取数据。
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();
}
}
}
In the code above, if first thread tries to get data and queue is empty i put in wait via wait(0) until other thread add data to queue an release from waiting via notify(). 在上面的代码中,如果第一个线程尝试获取数据并且队列为空,则我通过wait(0)进入等待状态,直到其他线程添加数据以排队通过notify()从等待状态释放。
Now I want to add another "lock" when queue is full and some one tries to add more data to it: 现在,我想在队列已满时添加另一个“锁”,并且有人尝试向其中添加更多数据:
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);
}
The result is not what I expect , I guess that i get a dead lock cause process is stuck. 结果不是我所期望的,我猜我死锁原因进程卡住了。
UPDATE 更新
This is how I get data: 这是我获取数据的方式:
queueSize--;
startPointer = (startPointer + 1) % mqueueSize;
data = (String) queue[startPointer];
this is how i add data 这就是我添加数据的方式
queueSize++;
endPointer = (endPointer + 1) % mqueueSize;
queue[endPointer] = data;
public synchronized boolean isEmpty() {
return queueSize== 0;
}
public synchronized boolean isFull() {
return queueSize== mqueueSize;
}
Why do you have three synchronized
statements? 为什么会有三个
synchronized
语句? The wait(0)
only releases the lock on this
, so just keep that one and dump the synchronized
from the method and the synchronized(myLock)
. 在
wait(0)
只释放上的锁this
,所以还是一个和转储synchronized
从方法和synchronized(myLock)
Whenever you call wait on some object (in this case you are calling on this
), the lock on that object is automatically released to allow the other thread to proceed. 每当您在某个对象上调用wait(在这种情况下,您正在调用
this
)时,该对象上的锁都会自动释放,以允许其他线程继续执行。 But you are never calling wait on myLock
(and nor should you, because you are calling on this
already). 但是,您永远不要在
myLock
上调用wait(也不应该,因为您已经在调用this
)。 That part is redundant and causes the deadlock. 这部分是多余的,并导致死锁。
Consider this scenario: the thread that is supposed to add takes the lock on myLock
but finds the queue full, so it waits. 考虑这种情况:应该添加的线程在
myLock
上myLock
了锁定,但发现队列已满,因此它等待。 This wait does not release the lock on myLock
. 此等待不会释放
myLock
上的锁。 The other thread wants to take data but cannot enter the synchronized
block because the first thread did not release the lock on myLock
. 另一个线程想要获取数据,但不能进入
synchronized
块,因为第一个线程没有释放myLock
上的锁。
Conclusion: remove the synchronized(myLock)
blocks. 结论:删除
synchronized(myLock)
块。
Why you don't take a look in java.util.BlockingQueue . 为什么不看一下java.util.BlockingQueue 。 Probably it will be useful in your situation.
可能对您的情况很有用。
Particularly take a look at java.util.LinkedBlockingQueue , where if you specify the queue's capacity in the constructor, then the queue will block. 特别要看一看java.util.LinkedBlockingQueue ,如果您在构造函数中指定队列的容量,则队列将阻塞。
Remove the synchronized
keyword from your method signatures, as that implies you hold the this
monitor for the whole method call -- the synchronized(this)
blocks are simply redundant. 从方法签名中删除
synchronized
关键字,因为这意味着您在整个方法调用中都拥有this
监视器synchronized(this)
块只是多余的。
EDIT: 编辑:
...Then call wait and notify on myLock
rather than this
. ...然后调用wait并在
myLock
而不是this
上myLock
通知。 And forget completely about synchronizing on this
. 并且完全忘记了与
this
同步。 This is because while waiting (on this
in your current code), you're not releasing the myLock
lock, so the other thread is not able to get to notify()
. 这是因为在等待(在
this
在当前的代码),你不释放myLock
锁,所以其他线程不能得到notify()
Replace if
with while
. if
用while
代替。 It won't hurt to double check, if the collection really become not empty/not full. 仔细检查集合是否真的变得不为空/不满也没有什么害处。
You don't really need two locks. 您实际上并不需要两个锁。 Single lock will work almost as well and should be much simpler.
单锁几乎可以正常工作,并且应该简单得多。
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();
}
All threads will wake up when something changes. 发生更改时,所有线程都将唤醒。 But if they can't do their work, they will
wait
for next notify
. 但是,如果他们无法完成工作,他们将
wait
下次notify
。
As already mentioned, your code has too many synchronized
annotations. 如前所述,您的代码有太多
synchronized
注释。 Also, the condition to wait
on is checked in an if
conditional, but it should ideally be checked in a while
loop to avoid spurious wakeups . 同样,在
if
条件中检查要wait
的条件,但理想情况下应在while
循环中检查此条件,以避免虚假唤醒 。 Here is the outline of the code that fixes these. 这是修复这些问题的代码的概要。
// _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();
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.