当线程请求一个由其它线程持有的对象锁时,该线程会阻塞,而当线程请求由自己持有的对象锁时,如果该锁是重入锁,请求就会成功,否则阻塞。
java中获取锁的操作的粒度是“线程”,而不是“调用”,即不是每一次调用都是建立一个锁。
重入锁的一种实现方法是为每个锁关联一个线程持有者和计数器,当计数器为0时表示该锁没有被任何线程持有,那么任何线程都可能获得该锁而调用相应的方法;当某一线程请求成功后,JVM会记下锁的持有线程,并且将计数器置为1;此时其它线程请求该锁,则必须等待;而如果同一个线程再次请求这个锁,就可以再次拿到这个锁,同时计数器会递增;当线程退出同步代码块时,计数器会递减,如果计数器为0,则释放该锁。
看下面的例子,正是由于java的内置锁是可重入的,所以下面这段代码不会发生死锁:
public class Child extends Father{
public static void main(String[] args) {
new Child().doSomething();
}
public synchronized void doSomething(){
System.out.println("child");
super.doSomething();
}
}
class Father{
public synchronized void doSomething(){
System.out.println("Father");
}
}
输出结果:
child
Father
重入的错误理解:
原文链接
正确理解:
知乎问题链接