扫描下方二维码或者微信搜索公众号
菜鸟飞呀飞
,即可关注微信公众号,阅读更多Spring源码分析
和Java并发编程
文章。
问题
在阅读本文之前可以先思考一下以下两个问题
1.
ReentrantLock是如何在Java层面(非JVM层面)实现锁的?2.
什么是公平锁?什么是非公平锁?
简介
Lock
是JUC包下的一个接口,里面定义了获取锁、释放锁等和锁相关的方法,ReentrantLock
是Lock接口的一个具体实现类,它的功能是可重入地独占式地获取锁。这里有两个概念,可重入
和独占式
。可重入表示的是同一个线程能多次获取到锁。独占式表示的是,同一时刻只能有一个线程获取到锁。ReentrantLock
实现的锁又可以分为两类,分别是公平锁
和非公平锁
,分别由ReentrantLock类中的两个内部类FairSync
和NonfairSync
来实现。FiarSync和NonfairSync均继承了Sync类,而Sync类又继承了AbstractQueuedSynchronizer(AQS)类,所以ReentrantLock最终是依靠AQS来实现锁的。关于AQS的知识可以参考以下两篇文章。- 队列同步器(AQS)的设计原理
- 队列同步器(AQS)源码分析
- ReentrantLock有两个构造方法,一个无参构造方法,一个有参构造方法。通过无参构造方法创建对象时,创建的是非公平锁;有参构造方法中,可以传入一个boolean类型的变量,如果传入的是true,那么创建的是公平锁,如果传入的是false,那么创建的是非公平锁。
/**
* Creates an instance of {@code ReentrantLock}.
* This is equivalent to using {@code ReentrantLock(false)}.
*/
public ReentrantLock() {
sync = new NonfairSync();
}
/**
* Creates an instance of {@code ReentrantLock} with the
* given fairness policy.
*
* @param fair {@code true} if this lock should use a fair ordering policy
*/
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
公平锁
- 当向ReentrantLock的构造方法中传入true时,创建的是公平锁。公平锁的
lock()
和unlock()
方法实现是由FairSync类中的lock()
和release()
方法实现的(其中release()方法定义在AQS中)。
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock(true);
try{
lock.lock();
System.out.println("Hello World");
}finally {
lock.unlock();
}
}
获取锁
- 当调用lock.lock()时,会调用到FairSync.lock()方法,FairSync.lock()方法会调用AQS中的acquire()方法。
static final class FairSync extends Sync {
final void lock() {
// 调用acquire()获取同步状态
acquire(1);
}
}
-
在AQS的acquire()方法中会先调用子类的tryAcquire()方法,此时由于我们创建的是公平锁,所以会调用FairSync类中的tryAcquire()方法。(关于acquire()方法的详细介绍,可以参考:队列同步器(AQS)源码分析)。
-
tryAcquire()方法的作用就是获取同步状态(也就是获取锁),如果当前线程成功获取到锁,那么就会将AQS中的同步状态state加1,然后返回true,如果没有获取到锁,将会返回false。FairSync类上tryAcquire()方法的源码如下。
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();