java 在同一个对象上同步两次?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/249867/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 11:38:18  来源:igfitidea点击:

Synchronising twice on the same object?

javamultithreadingsynchronizationmutex

提问by Omar Kooheji

I was wondering if in Java I would get any odd behaviour if I synchronise twice on the same object?

我想知道在 Java 中,如果我在同一个对象上同步两次,我是否会得到任何奇怪的行为?

The scenario is as follows

场景如下

pulbic class SillyClassName {

    object moo;
    ...
    public void method1(){
        synchronized(moo)
        {
            ....
            method2();
            ....
        }
    }

    public void method2(){
        synchronized(moo)
        {
            doStuff();
        }
    }
}

Both methods use the object and are synchronised on it. Will the second method when called by the first method stop because it's locked?

两种方法都使用该对象并在其上同步。第二种方法在被第一种方法调用时会因为它被锁定而停止吗?

I don't think so because it's the same thread but I'm unsure of any other odd results that might occur.

我不这么认为,因为它是同一个线程,但我不确定可能会出现任何其他奇怪的结果。

回答by Leigh

Reentrant

可重入

Synchronized blocks use reentrantlocks, which means if the thread already holds the lock, it can re-aquire it without problems. Therefore your code will work as you expect.

同步块使用可重入锁,这意味着如果线程已经持有锁,它可以毫无问题地重新获取它。因此,您的代码将按您的预期工作。

See the bottom of the Java Tutorialpage Intrinsic Locks and Synchronization.

请参阅Java 教程页面Intrinsic Locks and Synchronization的底部。

To quote as of 2015-01…

引用截至 2015 年 1 月…

Reentrant Synchronization

Recall that a thread cannot acquire a lock owned by another thread. But a thread can acquire a lock that it already owns. Allowing a thread to acquire the same lock more than once enables reentrant synchronization. This describes a situation where synchronized code, directly or indirectly, invokes a method that also contains synchronized code, and both sets of code use the same lock. Without reentrant synchronization, synchronized code would have to take many additional precautions to avoid having a thread cause itself to block.

重入同步

回想一下,一个线程不能获得另一个线程拥有的锁。但是一个线程可以获得一个它已经拥有的锁。允许一个线程多次获取同一个锁可以实现可重入同步。这描述了一种情况,即同步代码直接或间接调用了一个也包含同步代码的方法,并且两组代码使用相同的锁。如果没有可重入同步,同步代码将不得不采取许多额外的预防措施来避免线程导致自身阻塞。

回答by Praveen Mookoni

I think we have to use reentrant lock for what you are trying to do. Here's a snippet from http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/ReentrantLock.html.

我认为我们必须对您要执行的操作使用可重入锁。这是来自http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/ReentrantLock.html的片段。

What do we mean by a reentrant lock? Simply that there is an acquisition count associated with the lock, and if a thread that holds the lock acquires it again, the acquisition count is incremented and the lock then needs to be released twice to truly release the lock. This parallels the semantics of synchronized; if a thread enters a synchronized block protected by a monitor that the thread already owns, the thread will be allowed to proceed, and the lock will not be released when the thread exits the second (or subsequent) synchronized block, but only will be released when it exits the first synchronized block it entered protected by that monitor.

我们所说的可重入锁是什么意思?简单地说,有一个与锁相关的获取计数,如果持有锁的线程再次获取它,获取计数就会增加,然后需要释放锁两次才能真正释放锁。这与同步的语义相似;如果一个线程进入一个由该线程已经拥有的监视器保护的同步块,则该线程将被允许继续,并且当线程退出第二个(或后续)同步块时不会释放锁,而只会释放锁当它退出第一个同步块时,它进入受该监视器保护的块。

Though I have not tried it, I guess if you want to do what you have above, you have to use a re-entrant lock.

虽然我没有尝试过,但我想如果你想做上面的事情,你必须使用可重入锁。

回答by Odell Damon

Java appears to fully support nested locks on one object by the same thread. This means that if a thread has an outer and an inner lock on an object, and another thread tries to lock on the same object, the second thread will be suspended until bothlocks have been released by the first thread.

Java 似乎完全支持同一线程对一个对象的嵌套锁。这意味着如果一个线程在一个对象上有一个外锁和一个内锁,而另一个线程试图锁定同一个对象,第二个线程将被挂起,直到第一个线程释放了这两个锁。

My testing was done under Java 6 SE.

我的测试是在 Java 6 SE 下完成的。

回答by Odell Damon

In java, the synchronizedkeyword on a method basically synchronizes on the current object, so in effect it's doing what you suggest above implicitly.

在 java 中,synchronized方法上的关键字基本上同步当前对象,因此实际上它正在执行您上面建议的隐式操作。

You won't experience problems with synchronizing on one object in one method and then synchronizing on the same object in another method because, as you say, the current thread already holds the lock on that object.

在一种方法中同步一个对象然后在另一种方法中同步同一个对象时,您不会遇到问题,因为正如您所说,当前线程已经持有该对象的锁。

回答by Hyman Leow

No problems. In your example, (once you fix your code to get rid of the compile warnings that you'll get ;) ), the synchronization ensures that the blocks in method1 and method2 will not execute simultaneously.

没问题。在您的示例中,(一旦您修复代码以消除您将收到的编译警告;)),同步可确保 method1 和 method2 中的块不会同时执行。

That's kind of the point of synchronization. :)

这就是同步点。:)



Edit: Sorry, missed parts of your question, but Phill answered it. To summarize, a single thread cannot deadlock itself.

编辑:对不起,错过了您的问题的一部分,但菲尔回答了它。总而言之,单个线程不能使自身死锁。

回答by RuntimeException

No, the second method will not stop if called by first. No odd results will occur (except a slight overhead for checking lock. This wont matter much. Java 6 onwards, you have lock coarsening in the JVM - http://java.sun.com/performance/reference/whitepapers/6_performance.html)

不,如果第一个调用第二个方法将不会停止。不会出现奇怪的结果(除了检查锁的轻微开销。这不会有太大影响。Java 6 以后,您在 JVM 中有锁粗化 - http://java.sun.com/performance/reference/whitepapers/6_performance.html)

For example, take a look at source code of java.util.Vector. There are lot of calls to other synchronized methods from within synchronized methods.

例如,查看 java.util.Vector 的源代码。同步方法中有很多对其他同步方法的调用。