使用synchronized语句的可重入同步行为

时间:2011-04-26 08:44:57

标签: java

我在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    

4 个答案:

答案 0 :(得分:8)

是的,同步块是可重入的。 ReentrantLock也是可重入的,如果您想自己编写块,您可能希望使用它,因为它具有更多的灵活性/功能。

我会确保任何锁定都是final如果锁定对象不能是最终的,那几乎肯定是一个错误(或混淆的来源)

出于比较目的,并非Java中的所有锁都是可重入的。 FileLock不是直接将请求传递给操作系统。

答案 1 :(得分:5)

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

答案 2 :(得分:4)

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

答案 3 :(得分:0)

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