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

本文共 1979 字,大约阅读时间需要 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/

你可能感兴趣的文章
Node-RED中使用node-red-node-ui-iframe节点实现内嵌iframe访问其他网站的效果
查看>>
Node-RED中使用Notification元件显示警告讯息框(温度过高提示)
查看>>
Node-RED中使用range范围节点实现从一个范围对应至另一个范围
查看>>
Node-RED中实现HTML表单提交和获取提交的内容
查看>>
Node-RED中将CSV数据写入txt文件并从文件中读取解析数据
查看>>
Node-RED中建立TCP服务端和客户端
查看>>
Node-RED中建立Websocket客户端连接
查看>>
Node-RED中解析高德地图天气api的json数据显示天气仪表盘
查看>>
Node-RED中通过node-red-ui-webcam节点实现访问摄像头并截取照片预览
查看>>
Node-RED安装图形化节点dashboard实现订阅mqtt主题并在仪表盘中显示温度
查看>>
Node-RED订阅MQTT主题并调试数据
查看>>
node-request模块
查看>>
Node.js 8 中的 util.promisify的详解
查看>>
node.js url模块
查看>>
Node.js Web 模块的各种用法和常见场景
查看>>
Node.js 函数是什么样的?
查看>>
Node.js 切近实战(七) 之Excel在线(文件&文件组)
查看>>
node.js 初体验
查看>>
Node.js 历史
查看>>
Node.js 在个推的微服务实践:基于容器的一站式命令行工具链
查看>>