2011-04-26 89 views
6

我在java类中有两个方法,它们都有一个使用同一对象进行同步的代码块。我明白,在JAVA同步方案中,线程获取的锁是可重入的。有了这个我可以安全地说下面的一段代码不会在所有情况下导致任何问题?使用同步语句的可重入同步行为

public class Someclass 
{ 
    private static final Object LCK_OBJ = new Object(); 
    //..... 

    publc void method1() 
    { 
    //some code.... 
    synchronized(LCK_OBJ) 
    { 
     //some sychronized code. 
     method2(..); 
    } 
    //some more code.... 
    } 

    protected static final void method2(..) 
    { 
     Someclass ref = null; 
     //some code which gets different other references of SomeClass in a loop.... 
     ref.method3(..); 
    } 

    publc void method3() 
    { 
    //some code.... 
    synchronized(LCK_OBJ) 
    { 
     //some sychronized code. 
    } 
    //some more code.... 
    } 

}//end of class  

回答

5

是的,你可以,但是这段代码不会编译:你正在从一个静态方法“method2”调用实例方法“method3”。除此之外:如果一个线程设法获得“method1”中的锁,如果仍然有“method3”中的锁。

+0

谢谢Tomasz Stanczak!在输入示例代码时,我错过了通过对象引用键入实例方法调用的方法。请耐心等待并答复答复。只要添加到我以前的查询中,当某个线程当前在method2内执行(从method1调用)时,如果某个其他线程试图执行方法1或方法3中的同步代码,我们可以肯定地说第二个线程将被阻塞,直到第一个线程完成执行方法1,方法2和方法3? – Muthu 2011-04-26 19:00:59

+0

是的,它会阻塞,直到释放锁,并且当第一个线程从method3和method2返回后离开方法1中的同步块时会发生这种情况。 – 2011-04-27 06:47:00

4

是的,同一个线程可以在同一个锁上多次输入​​块。注意不要以不同顺序获取其他锁,否则可能导致死锁。

8

是的,同步块是可重入的。 ReentrantLock也是可重入的,如果你想自己对块进行编码,你可能想要使用它,因为它具有更多的灵活性/功能性。

我会确保任何锁final如果锁定对象不能是最终的,那么几乎可以肯定的错误(或混乱的根源)

出于比较的目的,而不是在Java中所有的锁都折返。 FileLock不是因为它直接将请求传递给操作系统。

+0

@Stephen C,我的观点是您可以相信Java中的所有锁都是可重入的。 – 2011-04-26 08:58:57

+0

@Stephen C,够了。 – 2011-04-26 15:30:24

+0

感谢您对此行为的确认。在最后一个修饰语中,你是对的......这实际上是我在输入示例代码时错过了它的部分,尽管我的意思是(注意全部大写变量名)。对不起,再次感谢。 – Muthu 2011-04-28 19:04:35

0

尽管这段代码不会像前面提到的那样编译,但我们考虑一下method2不是静态的情况。从method1到method2再到method3的调用是重入同步的一个很好的例子。当一个线程启动时,它会创建一个新的堆栈run()放在堆栈底部。由于对method1的调用来自run(),所以它被添加到run()之上的堆栈中,然后进入堆栈中的method2和method3。此外,由于对象锁由方法2在堆栈上执行,锁在所有调用的同步API上保留。锁的释放通过展开堆栈中最顶端的方法(本例中为method3)开始,直到实际的api到达哪个调用同步。