当某个线程想要请求一个被其他线程持有的锁时,就只能进入阻塞状态,等待着这个锁被释放
但是设想一下,如果这个锁是被这个线程自己持有,然后这个线程再此请求获取这个锁,还是会被阻塞么?
答案是:不会,该请求能够成功
这就是可重入锁的一个简单理解,可以重入意味着我们对持有锁的判断依据是线程,一个线程能够获取由它自己所持有的锁。
可重入锁的简单实现逻辑:
为每一个锁关联一个持有者线程和计数值,当计数值为0时,意味着这个锁没有被任何线程持有,而如果有线程请求获取一个没有被持有的锁,JVM会把这个线程记录下来作为持有者线程,同时计数值加一,如果是相同的线程再次获取锁,那么这个计数值会继续加一,当线程退出同步代码块时,计数值就会减一,当减到0时,这个锁就会被释放。
下面使用synchronized关键字简单演示下可重入锁:
- 定义一个父类–动物类
/**
* 动物类
*/
public class Animal {
//做点事
public synchronized void doSomething() {
System.out.println("父类动物做点事");
}
}
- 定义一个子类狮虎兽类,继承动物类
/**
* 狮虎兽类
*/
public class LigerAnimal extends Animal {
@Override
public synchronized void doSomething() {
System.out.println("子类狮虎兽做点事");
//调用父类的doSomething()方法
super.doSomething();
}
}
调用子类的方法做测试:
public static void main(String[] args) throws Exception {
LigerAnimal ligerAnimal = new LigerAnimal();
ligerAnimal.doSomething();
}
可以看到子类继承了父类,重写了父类的方法,然后调用父类的方法。
子类和父类方法都加了synchronized关键字,所以在调用doSomething()方法时,都会去获取Animal上的锁,如果锁不可以重入,那么在子类调用doSomething()时,持有了锁,输出完"子类狮虎兽做点事",就无法再继续调用父类的doSomething()了,因为 super.doSomething()无法再获取Animal上的锁,这个锁已经被子类调用时被持有了,线程将永远停顿下去,因为执行不完代码,线程退出不了同步块,而真实情况是:
子类父类的方法都能输出