等待/通知死锁

发布于 2024-12-21 20:13:46 字数 1813 浏览 4 评论 0原文

我有一个队列,在“添加”和“获取”方法中具有一些阻塞机制,其中第一个线程添加数据,第二个线程获取数据。

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) 进行等待,直到其他线程将数据添加到队列中,然后通过 notification() 释放等待。

现在,当队列已满并且有人尝试向其中添加更多数据时,我想添加另一个“锁”:

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;
    }

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().

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;
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

失而复得 2024-12-28 20:13:47

为什么有三个synchronized语句? wait(0) 仅释放 this 上的锁,因此只需保留该锁并从方法和 中转储 synchronized同步(myLock)。

每当您对某个对象调用 wait(在本例中您正在调用 this)时,该对象上的锁就会自动释放,以允许其他线程继续进行。但是您永远不会在 myLock 上调用 wait (也不应该,因为您已经在调用 this 了)。该部分是多余的并导致死锁。

考虑这种情况:应该添加的线程获取了 myLock 上的锁,但发现队列已满,因此它等待。此等待不会释放 myLock 上的锁定。另一个线程想要获取数据,但无法进入 synchronized 块,因为第一个线程没有释放 myLock 上的锁。

结论:删除 synchronized(myLock) 块。

Why do you have three synchronized statements? 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).

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. But you are never calling wait on myLock (and nor should you, because you are calling on this already). 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. This wait does not release the lock on 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.

Conclusion: remove the synchronized(myLock) blocks.

埋情葬爱 2024-12-28 20:13:47

为什么你不看看java.lang. util.BlockingQueue。也许它对您的情况有用。

特别是看看 java.util.LinkedBlockingQueue,如果您在构造函数中指定队列的容量,则队列将阻塞。

Why you don't take a look in 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.

↙厌世 2024-12-28 20:13:47

从方法签名中删除 synchronized 关键字,因为这意味着您持有整个方法调用的 this 监视器 - synchronized(this)块只是多余的。

编辑:

...然后在 myLock 而不是 this 上调用 wait 和通知。并且完全忘记在 this 上进行同步。这是因为在等待时(在当前代码中的 this 上),您没有释放 myLock 锁,因此其他线程无法访问 通知()。

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.

EDIT:

...Then call wait and notify on myLock rather than this. And forget completely about synchronizing on 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().

深海夜未眠 2024-12-28 20:13:47

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();

}

当事情发生变化时,所有线程都会被唤醒。但如果他们无法完成工作,他们将等待下一个通知

Replace if with 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.

萌面超妹 2024-12-28 20:13:47

正如已经提到的,您的代码有太多synchronized 注释。此外,wait 的条件是在 if 条件中检查的,但理想情况下应该在 while 循环中检查,以避免 虚假唤醒。以下是修复这些问题的代码概要。

// _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();
  }
}

As already mentioned, your code has too many synchronized annotations. 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. 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();
  }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文