ReenterantLock分析

173 阅读3分钟

1.ReentrantLock源码分析

1.1ReentrantLock是什么?

  • 是Lock接口的一个实现。
  • 主要实现了可重入的独占锁的功能
  • 类似与synchronized关键字的功能

1.2ReentrantLock和synchronized对比

ReentrantLock功能更加强大,使用更为灵活:

  1. 可以非中断的获取锁
  2. 可以中断式的获取锁
  3. 超时获取锁
  4. 提供了公平锁和非公平锁synchronized是非公平锁

1.2.1公平锁和非公平锁

主要体现在锁的获取方式上。

1)公平锁

是多个线程按照申请获取锁的时间先后顺序来获取锁。

2)非公平锁

多个线程申请获取锁的顺序不是按照时间先后来获取锁。比如:抢占式获取锁。而且在高并发的情况下可能会有线程饥饿现象。

1.3 ReenterantLock的源码

ReenterantLock是Lock接口的实现类,里面重写了Lock接口的一些方法,例如lock(),unlock()等。同时ReenterantLock还有三个静态内部类。如下图:

image.png

其中,Sync静态内部类继承了AQS,所以在Sync中只需要指定获取锁的方式以及获取的是什么样子的锁以及释放锁的方式即可,其他的比如同步队列的运行和维护等,都已经在AQS中定义好了。ReenterantLock重写Lock方法,在这之中调用Sync重写AQS中的方法,完成可重入锁的实现。

image.png

可重入锁的无参构造的默认实现是非公平锁。如果想要实现公平锁,给构造方法传入一个boolean值true。如图:

image.png

1.3.1NonfairSync

就是非公平锁的实现,Lock接口中的lock()方法在Sync中还是没有重写,交由子类去重写,一个类实现公平锁,一个类实现非公平锁。NonfairSync是用来实现非公平锁的,如图:

image.png

可以看到,一个线程在调用lock()尝试时,就直接尝试使用CAS操作修改state的值,如果修改成功,这个线程就获取到锁了。而在等待队列中先进行排队获取锁的线程在他后面获取锁,这就是一个非公平锁。在修改失败后,才会加入到等待队列中。

除此之外,这还是一个可重入锁,可重入锁的逻辑在nonfairTryAcquire()(这个方法的实现在Sync中)中实现。如图:

image.png

1.3.2 FairSync

是公平锁的实现,同样重写了lock()方法,在lock()方法中直接调用了AQS的acquire方法,在AQS的acquire方法中,又会调用这个静态内部类实现的tryAcquire方法。在这个方法中,实现了公平的可重入锁机制。如图:

image.png

那么公平锁的逻辑是怎么实现的,如图:

image.png

满足以上条件返回true,加上判断条件上的!,那么在判断线程是否可以通过CAS操作获取锁时就是false,那么线程就不能获取锁。通过以上逻辑我们知道,只要队列中还有线程,那么新来的线程就不能直接获取锁,必须进入到队列中排队,这样就实现了公平锁。

重入锁的逻辑,公平锁和非公平锁都是一样的

1.3.3 释放锁的逻辑

在静态内部类NonfairSyncFairSync中都没有释放锁的逻辑,它们共用在Sync中的释放锁的逻辑。如图:

image.png

1.3.4 可中断锁和超时获取锁

可中断锁和超时获取锁都已经在AQS中实现了,我们只需要实现获取锁的方式。超时获取锁和可中断获取锁使用的是公平锁和非公平锁的获取方式(tryAcquire方法)。所以,在重写了获取锁的逻辑后,可中断锁和超时获取锁也就实现了。