前言
接下来会用 3-4 篇文章来分析 ReentrantLock
的源码,本文先来打点基础。
阅读本文之前需了解以下内容:
- 原子性的概念
- CAS 的概念
ReentrantLock
是独占锁且可重入ReentrantLock
既可以是非公平锁,也可以是公平锁
以上小知识也可以参考上一篇文章ReentrantLock 源码分析 - 并发小知识
正文
分析 ReentrantLock
之前,需要简单了解以下三个基础类:
- sun.misc.Unsafe
- java.util.concurrent.locks.LockSupport
- java.util.concurrent.locks.AbstractQueuedSynchronizer
这三个类,本文会粗略提一下他们的功能,有个大概印象即可, 第三个类是重点, 后面的文章还会详细讲到。
1. Unsafe 类
Unsafe
类位于 JDK 的 rt.jar 包中, 它提供了硬件级别的 原子性 操作,Unsafe
类中的方法都是 native 方法。
我们主要看下面三个方法:
// 比较 Object 中偏移量为 offset 的变量的值是否与 expect 相等,
// 如果相等则使用 update 更新并返回 true
// 如果不相当,返回 false
public final native boolean compareAndSwapInt(Object o, long offset, int expect, int update);
// 阻塞当前线程
public native void park(boolean var1, long var2);
// 唤醒调用 park 方法而阻塞的线程
public native void unpark(Object var1);
2. LockSupport 类
LockSupport
类中也有相应的 park
和 unpark
方法,内部实现也是基于 Unsafe
类对应的方法, 当然作用也是一样的。
public static void park(Object blocker) {
// 省略部分代码
unsafe.park()
}
public static void unpark(Thread thread) {
// 省略部分逻辑
unsafe.unpark()
}
3. AbstractQueuedSynchronizer 类
AbstractQueuedSynchronizer
是分析的重点, 来详细看下。
3.1 AbstractQueuedSynchronizer 的方法
AbstractQueuedSynchronizer
类通过调用 LockSupport
和Unsafe
对应的方法去实现以下三个功能。
// 获取独占资源
public final void acquire(int arg) {
// 最终会调用
LockSupport.park();
}
// 释放独占资源
public final boolean release(int arg) {
// 最终会调用
LockSupport.unpark();
}
// CAS 操作
protected final boolean compareAndSetState(int expect, int update) {
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
3.2 AbstractQueuedSynchronizer 简单介绍
AbstractQueuedSynchronizer
是一个抽象类,中文可以翻译为 抽象同步队列, 简称 AQS,是一个双向队列,队列中的节点定义为 Node
,Node
里面存放有具体的线程,简易图如下:
AbstractQueuedSynchronizer
是实现 ReentrantLock
, ReentrantReadWriteLock
, CountDownlatch
等同步器的基础。
3.3 AbstractQueuedSynchronizer 的作用
我们就拿 ReentrantLock
来说明 AbstractQueuedSynchronizer
的作用。ReentrantLock
内部持有 AbstractQueuedSynchronizer
相应实现的引用。
// ReentrantLock 源码
public class ReentrantLock implements Lock, java.io.Serializable {
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer {
// 省略部分内容
}
}
来看一个ReentrantLock
的具体使用
ReentrantLock lock = new ReentrantLock();
// 对共享资源进行操作
public void dealShareResource() throws InterruptedException {
try {
lock.lock();
// doSomething
} finally {
lock.unlock();
}
}
从代码使用上看,并不能看出 AQS 到底起到了什么作用,下面用一张图来描述 AQS 在 lock 过程中的作用:
假设有三个线程同时去调用 dealShareResource
方法,会去获取锁, 如果 thread1
先抢到锁,那么其余的线程(thread2,thread3
)就会放到 AQS 队列当中,其他细节这里先不提。
3.4 AbstractQueuedSynchronizer 的属性
我们知道 ReentrantLock
是一个可重入锁,而它的这个特性就是基于 AbstractQueuedSynchronizer
的 state
属性
属性定义
private volatile int state;
-
作用一
- 一个线程过来,如果
state
为 0 表示锁没有被占用 - 调用
compareAndSetState(0, 1)
方法 - 期望获得的是 0,如果是 0,就把
state
更新为 1
- 一个线程过来,如果
-
作用二
- 一个线程 A 过来, 如果
state > 0
,表示锁被线程 B 占用了, - 然后判断 线程A 是否就是 线程 B
- 如果是
state++
, 否则放入 AQS 队列
- 一个线程 A 过来, 如果
总结
本文是对阅读 ReentrantLock
源码之前做的准备工作, 简单了解了三个类的基本作用:
- sun.misc.Unsafe
- java.util.concurrent.locks.LockSupport
- java.util.concurrent.locks.AbstractQueuedSynchronizer
他们的调用关系是由下而上。 ReentrantLock
持有AbstractQueuedSynchronizer
具体实现,通过调用ReentrantLock
的 lock
和unlock
方法,最终会去调用 AbstractQueuedSynchronizer
相应的方法,最后实现同步功能。