JDK8 源码解读:ReentrantLock - 变量与结构

前言

ReentrantLock 的许多具体实现都在 AbstractQueuedSynchronizer 中,因此本应该先阅读 AQS 的源码。

但是我在阅读时就发现,由于 AQS 中同时包含独占锁包容锁的实现,因此直接阅读很多地方很费解,因此我觉得从某种锁入手同步阅读 AQS 效果会更好。

虽说我个人认为不先进行 AQS 的代码阅读,但是我们还是应该要先阅读里面用到的变量。

PS:Alt + 7 调出 Structure 工具方便对方法变量进行快速定位,本次源码中暂时不涉及 ReentrantLock 中的条件部分

ReentrantLock 与 AQS 的关系

ReentrantLock: 主要提供何时加锁何时解锁的逻辑,至于加锁解锁是设计到的底层数据结构的变化,全部由 AQS 提供

AbstractQueuedSynchronizer: 队列同步器,底层提供了线程加锁,解锁与重入的具体操作实现,是 ReentrantLock 的核心组件

ReentrantLock 变量

sync:同步器

Sync 同步器继承了 AQS,为 ReentrantLock 提供核心实现

SyncReentrantLock 中根据不同的构造函数主要有两个实现,分别对应公平锁非公平锁

private final Sync sync;

AQS 变量

head:等待队列头结点

指向等待队列首元素的头指针
延迟初始化,除了初始化,只能通过 setHeader 修改
如果 head 存在,保证 head 节点不会被 Cancelled(线程取消了等待)
head 表示正在进行的节点,因此不满足等待的情况,因此不可能为 Cancelled

private transient volatile Node head;

tail:等待队列尾结点

指向队列尾元素的尾指针
延迟初始化,只通过 enq 方法来新增等待节点

private transient volatile Node tail;

state:同步状态

  • 0:未进入同步
  • 1:进入同步状态
  • >1:说明线程重入了,值为 1 + 重入次数

因此这个字段很重要,重入次数靠它实现

private volatile int state;

用于原子操作的变量

这几个参数就不一一介绍了,官方注释也很清晰,意思就是这几个是用来对类中的某些变量进行原子性 CAS 操作的,调用的是底层 C 语言中的方法

private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long stateOffset;
private static final long headOffset;
private static final long tailOffset;
private static final long waitStatusOffset;
private static final long nextOffset;

static {
    try {
        stateOffset = unsafe.objectFieldOffset
            (AbstractQueuedSynchronizer.class.getDeclaredField("state"));
        headOffset = unsafe.objectFieldOffset
            (AbstractQueuedSynchronizer.class.getDeclaredField("head"));
        tailOffset = unsafe.objectFieldOffset
            (AbstractQueuedSynchronizer.class.getDeclaredField("tail"));
        waitStatusOffset = unsafe.objectFieldOffset
            (Node.class.getDeclaredField("waitStatus"));
        nextOffset = unsafe.objectFieldOffset
            (Node.class.getDeclaredField("next"));

    } catch (Exception ex) { throw new Error(ex); }
}

AQS 等待队列节点 Node

静态参数

涉及模式

  • SHARED: 标记表示节点正在共享模式中等待
  • EXCLUSIVE: 标记表示节点正在独占模式下等待
/** Marker to indicate a node is waiting in shared mode */
// 标记表示节点正在共享模式中等待
static final Node SHARED = new Node();
/** Marker to indicate a node is waiting in exclusive mode */
// 标记表示节点正在独占模式下等待
static final Node EXCLUSIVE = null;

等待状态

由于暂时不涉及 ReentrantLock 条件部分,因此不涉及条件等待队列部分,等待状态仅涉及
CANCELLED,SIGNAL ,以及INITIALIZE

  • CANCELLED: 1,取消状态,表示线程已经无法再运行
  • INITIALIZE: 0,初始化状态,虽然代码中并没有明确指出
  • SIGNAL : -1,待唤醒状态,一般表示线程未轮到,在队列中等待唤醒
  • CONDITION : -2,线程等待在条件变量队列中
  • PROPAGATE : -3,在共享模式下,无条件传播releaseShared状态,引入这个状态是为了解决共享锁并发释放引起线程挂起的bug 6801020
/** waitStatus value to indicate thread has cancelled */
// 表示线程取消了等待,比如取得锁的过程中报异常情况下
 static final int CANCELLED =  1;
 /** waitStatus value to indicate successor's thread needs unparking */
 // 表示后续节点需要被唤醒
 static final int SIGNAL    = -1;
 /** waitStatus value to indicate thread is waiting on condition */
 // 线程等待在条件变量队列中。
 static final int CONDITION = -2;
 /**
  * waitStatus value to indicate the next acquireShared should
  * unconditionally propagate
  */
 // 在共享模式下,无条件传播releaseShared状态
 // 引入这个状态是为了解决共享锁并发释放引起线程挂起的bug 6801020
 static final int PROPAGATE = -3;

变量

waitStatus:等待状态

用于接收具体的等待状态,本次只涉及 CANCELLED,SIGNAL 以及初始化状态

volatile int waitStatus;

prev:指向前一个节点

此参数在进入队列时分配,出队列时清空,便于 GC
这个节点必定会被找到,因为 head 节点是无法取消的,因此至少能找到 head 节点
作用1: 用来检查 waitStatus 状态
作用2: 在上一个任务被取消后,会一直循环直到找到上一个没被取消的节点

volatile Node prev;

next:指向后一个结点的指针

此参数在进入队列时分配,出队列时清空,便于 GC
enq 时候并未分配这个参数,因此这个参数为 null,并不代表这个节点为尾结点
特殊情况:后一个节点 prev 在 CAS 还未分配完的情况下,前一个节点的 next 此时为空,但是并非尾结点
如果下个节点为 null,需要从尾结点向前扫描以此进行双重验证
假如下个节点被取消了,并非下个节点为 null,而且下个节点的 next 指向为 null

volatile Node next;

thread:当前线程

volatile Thread thread;

nextWaiter:指向下一个等待在条件变量队列中的节点

指向下一个等待在条件变量队列中的节点
因为条件队列仅在独占模式时才被访问(EXCLUSIVE)
因此只需要一个简单链表队列来保存条件变量队列中的节点
将它们放入队列重新获取许可,由于条件队列仅在独占模式下使用,因此使用特殊值来代表共享模式

Node nextWaiter;

结尾

JDK8 源码解读:ReentrantLock - 核心方法

源码

JDK 1.8 源码阅读-注释版

JDK 1.8 源码阅读

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值