简体   繁体   English

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

[英]Using 'this' versus another object as lock in synchronized block with wait and notify

I have two blocks of code, one waits for the other to notify it. 我有两个代码块,一个等待另一个通知它。

synchronized(this) {
    wait();
}

and

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

Weirdly enough that didn't wait for the notify while this did: 奇怪的是,在这样做时没有等待通知:

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

and

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

I'm very curious about the difference of both sets, and why the first one worked while the other didn't. 我对这两组的差异非常好奇,为什么第一组有效,而另一组没有。 Note that the two blocks reside in two different threads on two different methods (if that helps). 请注意,这两个块位于两个不同方法的两个不同线程中(如果这有帮助)。

I hope someone could explain why this is so. 我希望有人可以解释为什么会这样。 I edited my question so it would be more detailed. 我编辑了我的问题所以它会更加详细。

You can use any object you like. 您可以使用任何您喜欢的对象。 However, it is generally clearer to other programmers to see an explicit lock object. 但是,其他程序员通常更清楚地看到显式锁对象。

My wild guess as to why this didn't work for you is you had a different this in scope. 我的胡乱猜测,为什么this不适合你的工作是你有不同的this范围。 (ie, in an anonymous function/callback). (即,在匿名函数/回调中)。 You can be explicit about which this to use by appending the class name, eg, WonderClass.this - again a reason why this is not as clear. 您可以通过附加类名来明确说明要使用哪个类,例如, WonderClass.this - this也是为什么this不清楚的原因。 (edit: actually WhateverClass.this won't help you if this really is a different instance) (编辑:实际上是WhateverClass.this如果this真的是一个不同的实例, this对你没有帮助)

Also do read this: http://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html - I generally find it easier to put all the thread-unsafe code into small synchronized methods (which do an implict lock on this) 另请阅读: http//docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html - 我通常会发现将所有线程不安全的代码放入小型同步方法(执行隐含锁定)更容易在此)

It didn't work because you synchronized on this which in two different threads pointed to two different Thread objects. 它没有工作,因为你在同步this这两个不同的线程指出,两个不同的 Thread对象。

Synchronization with wait() and notify() would only work properly when you synchronize on the same object for locking like the objectLock that you used later on. wait()notify()同步只有在同一个对象上进行同步锁定时才能正常工作,就像稍后使用的objectLock一样。

EDIT: If the two thread instances belonged to the same MyThread class then to achieve the effect that you thought you're code was having, you would have to acquire a lock on their class object itself: 编辑:如果两个线程实例属于同一个MyThread类,那么为了达到您认为代码所具有的效果,您必须获取其类对象本身的锁定:

synchronized(MyThread.class)

When you say the two blocks reside in two different threads that makes me think they're not locking on the same object because this is not the same thing. 当你说这两个块存在于两个不同的线程中时,我认为它们并没有锁定在同一个对象上,因为this不是一回事。 When you name an explicit lock you're using the same thing to lock on. 当您命名一个显式锁定时,您使用相同的东西来锁定。

By the way you should call wait in a loop, like 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
}

Without this you will be vulnerable to spurious wakeups (not all notifications come from your application code) and the order in which wait and notify are called becomes problematic (if you have two threads and one notifies before the other waits then that notification never gets seen). 如果没有这个,您将容易受到虚假唤醒的攻击(并非所有通知都来自您的应用程序代码),并且调用waitnotify的顺序会出现问题(如果您有两个线程,并且在另一个等待之前通知,那么通知永远不会被看到)。

I'd advise using the Monitor pattern ( http://en.wikipedia.org/wiki/Monitor_(synchronization) ) anyway, that could save you from errors later on, especially as your use case gets more complex: 无论如何,我建议使用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();
    }
}

That way everything is nicely encapsulated and protected (I don't usually use private modifiers in examples, but you might want to enforce additional "privacy" in your code, specifically making the condition private .) 这样一切都很好地封装和保护(我通常不会在示例中使用private修饰符,但您可能希望在代码中强制执行额外的“隐私”,特别是将condition private 。)

As you can observe, in my condition loop there is wait() call, as opposed to your example where you have notify() in the loop instead. 正如你所看到的,在我的条件循环中有wait()调用,而不是你在循环中有notify()例子。 In most use cases doing what you did with notify is a mistake, although I can't speak for your particular case as you didn't provide us with enough details. 在大多数用例中,使用notify做的事情是错误的,虽然我不能代表您的具体情况,因为您没有向我们提供足够的详细信息。 I am willing to bet yours is the typical one though, for which the Monitor pattern applies beautifully. 我愿意打赌你的是典型的,其中Monitor模式适用得很漂亮。

The usage scenario is along the following: thread that wants to wait for something calls waitForSomething and another thread may cause it to continue by invoking signal method which will set the condition flag. 使用场景如下:想要等待某事的线程调用waitForSomething而另一个线程可能通过调用将设置条件标志的signal方法使其继续。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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