使用'this'与另一个对象锁定同步块中的wait和notify

时间:2013-05-23 14:21:52

标签: java multithreading synchronized synchronized-block

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

synchronized(this) {
    wait();
}

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

奇怪的是,没有等到通知的时候:

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

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

我很好奇这两组的差异,以及为什么第一组有效而另一组没有。请注意,这两个块位于两个不同方法的两个不同线程中(如果有帮助)。

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

4 个答案:

答案 0 :(得分:2)

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

我猜测this为什么不适合你的猜测是你的范围不同this。 (即,在匿名函数/回调中)。您可以通过附加类名来明确说明要使用哪个类,例如WonderClass.this - 这也是this不清楚的原因。 (编辑:如果WhateverClass.this确实是一个不同的实例,实际上this将无法帮助您

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

答案 1 :(得分:2)

它无效,因为您在this上同步了两个不同的主题指向两个不同的 Thread对象。

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

修改 的 如果两个线程实例属于同一个MyThread类,那么为了达到您认为代码所具有的效果,您必须获得对其类对象本身的锁定:

synchronized(MyThread.class)

答案 2 :(得分: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
}

如果没有这个,您将容易受到虚假唤醒(并非所有通知都来自您的应用程序代码)以及waitnotify被调用的顺序成为问题(如果您有两个线程和一个在其他人等待之前通知通知永远不会被看到。)

答案 3 :(得分: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 { {1}}。)

正如您所观察到的,在我的条件循环中有private调用,而不是您在循环中有wait()的示例。在大多数用例中,使用notify()执行的操作是错误的,但我不能代表您的具体情况,因为您没有向我们提供足够的详细信息。我愿意打赌你的是典型的,因为Monitor模式适用得很漂亮。

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