博客
关于我
ReentrantLock 源码分析 - AbstractQueuedSynchronizer 详解(一)
阅读量:480 次
发布时间:2019-03-06

本文共 1964 字,大约阅读时间需要 6 分钟。

前言

上一篇文章介绍了AbstractQueuedSynchronizer (AQS)的基本概念及其在Java并发编程中的作用。本文将基于JDK 8的源码,深入分析AQS及其在ReentrantLock中的应用。阅读本文前,建议了解共享锁和独占锁的基本概念。

正文

上一篇文章提到CountDownlatch、ReentrantLock、ReentrantReadWriteLock以及Semaphore等并发工具类都基于AQS实现。为了支持这些功能,AQS需要具备高度灵活和通用的功能。例如:

  • ReentrantLock(独占锁)通过调用AQS的acquire方法获取独占资源。
  • ReentrantReadWriteLock(共享锁)通过调用AQS的acquireShared方法获取共享资源。
  • 这些方法均呼吁了compareAndSetState方法来执行CAS操作。

虽然上述只是两个类的区别,但Java.util.concurrent包中包含多种工具类,因此我们无需全面理解AQS的所有功能。接下来,我们将重点分析AQS在ReentrantLock中的作用。


1. Node类

Node类是AQS的内部类,主要用于管理队列中的节点。其属性包括:

  • prevnext:分别表示前驱和后驱指针。
  • thread:存储当前线程标识。
  • SHARED:标记当前线程因抢夺共享资源而进入队列。
  • EXCLUSIVE:标记当前线程因抢夺独占资源而进入队列。
  • waitStatus:表示当前线程的等待状态,可选值包括CANCELLED、CONDITION、SIGNAL和PROPAGATE。

AQS是一个双向队列,队列中的元素是Node对象。


2. AQS的核心属性

AQS维护以下关键属性:

  • headtail:分别指向队列的头节点和尾节点。
  • state:表示当前锁的状态。例如,在ReentrantLock中,state即为重入次数。

3. AQS的核心方法

AQS提供了几个关键方法:

  • acquire(int arg):尝试获取独占资源。当获取失败时,将当前线程放入队列并阻塞。
  • release(int arg):释放独占资源,并唤醒队列中的线程。
  • compareAndSetState(long expect, long update):通过CAS操作来更新状态。

3.1 acquire方法

acquire方法的大致逻辑如下:

public final void acquire(int arg) {    if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) {        selfInterrupt();    }}
  • tryAcquire尝试获取锁,如果成功则返回true,否则返回false。
  • acquireQueued将当前线程挂入队列并阻塞。
  • selfInterrupt在获取失败后唤醒当前线程。

3.2 release方法

release方法的大致逻辑如下:

public final boolean release(int arg) {    if (tryRelease(arg)) {        Node h = head;        if (h != null && h.waitStatus != 0) {            unparkSuccessor(h);        }        return true;    }    return false;}
  • tryRelease尝试释放锁,成功时返回true,否则返回false。
  • unparkSuccessor唤醒队列中的线程,并调用LockSupport.unpark方法。

3.3 compareAndSetState方法

compareAndSetState方法通过unsafe类的native方法实现CAS操作。例如:

protected final boolean compareAndSetState(long expect, long update) {    return unsafe.compareAndSwapLong(this, stateOffset, expect, update);}

总结

AQS是一个高度灵活的同步设施,作为许多并发工具类(如ReentrantLock)的基础。它通过双向队列管理线程,并支持CAS操作来实现高效的信号传递。当多个线程竞争锁时,未成功获取锁的线程会被放入队列,直到锁被释放并唤醒。AQS的引用使相关锁类能够支持复杂的并发场景,具体实现方式需结合各类的具体需求来定制。

转载地址:http://jgpdz.baihongyu.com/

你可能感兴趣的文章
Quartz中时间表达式的设置-----corn表达式
查看>>
poj 1035
查看>>
POJ 1061 青蛙的约会 (扩展欧几里得)
查看>>
Quartz2.2.1简单使用
查看>>
POJ 1080 Human Gene Functions(DP:LCS)
查看>>
Quant 开源项目教程
查看>>
POJ 1088 滑雪
查看>>
POJ 1095 Trees Made to Order
查看>>
POJ 1113 Wall(计算几何--凸包的周长)
查看>>
poj 1125Stockbroker Grapevine(最短路)
查看>>
Qualitor processVariavel.php 未授权命令注入漏洞复现(CVE-2023-47253)
查看>>
poj 1151 (未完成) 扫描线 线段树 离散化
查看>>
POJ 1151 / HDU 1542 Atlantis 线段树求矩形面积并
查看>>
poj 1163 数塔
查看>>
POJ 1177 Picture(线段树:扫描线求轮廓周长)
查看>>
Qualitor checkAcesso.php 任意文件上传漏洞复现(CVE-2024-44849)
查看>>
POJ 1182 食物链(并查集拆点)
查看>>
POJ 1185 炮兵阵地 (状态压缩DP)
查看>>
POJ 1195 Mobile phones
查看>>
POJ 1228 Grandpa's Estate (稳定凸包)
查看>>