重入锁 ReentrantLock, 顾名思义,就是支持重进入的锁,它表示该锁能够支持一个线程对资源的重复加锁。除此之外,该锁还支持获取锁时的公平和非公平性选择。默认是非公平性的。

synchronized 关键字隐式的支持重进入。

ReentrantLock 是独占锁,某个时刻只有一个线程可以获取该锁。

实现重进入

重进入是指任意线程在获取到锁之后能够再次获取该锁而不会被锁所阻塞,该特性的实现需要解决以下两个问题。

  1. 线程再次获取锁。锁需要去识别获取锁的线程是否为当前占据锁的线程,如果是,则再次成功获取。
  2. 锁的最终释放。线程重复 n 次获取了锁,随后在第 n 次释放该锁后,其他线程能够获取到该锁。

实现公平锁

对于非公平锁,只要 CAS 设置同步状态成功,则表示当前线程获取了锁,而公平锁则不同。
公平锁的 tryAcquire 方法 与 非公平锁的 nonfairTryAcquire(int acquires) 比较,唯一不同的位置为判断条件多了 hasQueuedPredecessors() 方法, 即加入了同步队列中当前节点是否有前驱节点的判断,如果该方法返回 true,则表示有线程比当前线程更早地请求获取锁,因此需要等待前驱线程获取并释放锁之后才能继续获取锁。

为什么需要可重入锁?

可重入锁最大的作用是避免死锁。
子类改写了父类的 synchronized 方法,然后调用父类中的方法,此时如果内置锁不是可重入的,那么这段代码将产生死锁。

  1. public class Widget{
  2. public synchronized void doSomething(){
  3. ........
  4. }
  5. }
  6. public class LoggingWidget extends Widget{
  7. public synchronized void doSomething(){
  8. super.doSomething();
  9. }
  10. }