简体   繁体   English

等待/通知死锁

[英]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. 考虑这种情况:应该添加的线程在myLockmyLock了锁定,但发现队列已满,因此它等待。 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而不是thismyLock通知。 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 . ifwhile代替。 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM