3

我有两个代码块,一个等待另一个通知它。

synchronized(this) {
    wait();
}

while(condition) {
    //do stuff
    synchronized(this) {
        notify();
    }
}

奇怪的是,这样做时并没有等待通知:

synchronized(objectLock) {
    objectLock.wait();
}

while(condition) {
    //do stuff
    synchronized(objectLock) {
        objectLock.notify();
    }
}

我很好奇两组的区别,以及为什么第一组有效而另一组无效。请注意,这两个块以两种不同的方法驻留在两个不同的线程中(如果有帮助的话)。

我希望有人能解释为什么会这样。我编辑了我的问题,所以它会更详细。

4

4 回答 4

2

它不起作用,因为您this在两个不同的线程中同步了指向两个不同的 Thread对象。

只有当您在同一个对象上同步以进行锁定时,与wait()和同步notify()才能正常工作,就像objectLock您稍后使用的那样。

编辑: 如果两个线程实例属于同一个MyThread类,那么要实现您认为代码所具有的效果,您必须在其类对象本身上获取锁:

synchronized(MyThread.class)
于 2013-05-23T14:33:16.853 回答
2

你可以使用任何你喜欢的对象。但是,其他程序员通常更清楚地看到显式锁定对象。

this我对为什么不适合你的疯狂猜测是你的this范围不同。(即,在匿名函数/回调中)。您可以通过附加类名来明确使用哪个 this,例如WonderClass.this- 再次说明为什么this不那么清楚。(编辑:如果真的是不同的实例,实际上WhateverClass.this不会帮助你)this

还请阅读: http ://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html - 我通常发现将所有线程不安全的代码放入小的同步方法中更容易(它执行隐式锁定对此)

于 2013-05-23T14:26:54.953 回答
1

当您说这两个块驻留在两个不同的线程中时,这让我认为它们没有锁定同一个对象,因为它们this不是同一件事。当您命名显式锁时,您使用的是相同的东西来锁定。

顺便说一句,您应该wait循环调用,如下所示:

synchronized(someLock) {
   while (!someCondition) {
       wait();
   }
   // now the thread has the lock and it can do things 
   // knowing for sure that someCondition is true
}

wait如果没有这个,您将很容易受到虚假唤醒的影响(并非所有通知都来自您的应用程序代码),并且调用和 的顺序notify变得有问题(如果您有两个线程并且一个在另一个等待之前通知,那么该通知永远不会被看到)。

于 2013-05-23T14:35:04.840 回答
1

无论如何,我建议使用 Monitor 模式(http://en.wikipedia.org/wiki/Monitor_(synchronization)),这可以在以后避免错误,尤其是当您的用例变得更加复杂时:

class Monitor
{
    /** Initialised to `false` by default in Java. */
    boolean condition;

    synchronized void waitForSomething()
    {
        while(!condition)
        {
            wait();
        }
    }

    synchronized void signal()
    {
        condition = true;

        notify();
    }
}

这样,所有内容都被很好地封装和保护(我通常不在private示例中使用修饰符,但您可能希望在代码中强制执行额外的“隐私”,特别是制作condition private.)

如您所见,在我的条件循环中有wait()调用,而不是您notify()在循环中的示例。在大多数用例中,做你所做的事情notify是一个错误,尽管我不能代表你的具体情况,因为你没有向我们提供足够的细节。我敢打赌你的就是典型的,Monitor 模式非常适用。

使用场景如下:想要等待某事调用的线程和另一个线程可能会通过调用将设置条件标志的方法waitForSomething使其继续。signal

于 2013-05-23T14:47:09.163 回答