我在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
答案 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来启动的。到达哪个调用同步。