(笔者推荐)【Java权威指南】「官方文档-中英互译」AQS的源码注释分析,贯穿总体核心流程!

本文主要是介绍(笔者推荐)【Java权威指南】「官方文档-中英互译」AQS的源码注释分析,贯穿总体核心流程!,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前提说明

本文主要针对于Java官方文档中的先关的官方注释进行中英文互译,保证了源码坐着的设计思路以及相关知识技能介绍分析等,本文主要进行介绍AQS的源码官方注释的含义介绍,对Java技术有一定领悟的达人会有帮助!


Java官方文档-介绍相关什么是CLH队列(AQS的实现基础)
CLH介绍定义

CLH是基于单向链表的高性能,公平的自旋锁,申请枷锁和线程只需要在本地变量上自旋,来减少CPU缓存和主内存的同步次数,从而降低了总线的内存的开销。


CLH的概念(英文版)

The wait queue is a variant of a “CLH” (Craig,Landin and Hagersten) lock queue. CLH
locks are normally used for spinlocks. We instead use them for blocking synchronizers by including explicit(“prev” and “next”) links plus a “status” field that allow nodes to signal successors when releasing locks, and handle cancellation due to interrupts and timeouts. The status field includes bits that track whether a thread needs a signal (using LockSupport.unpark),Despite these additions,we maintain most CLH locality properties.

CLH的概念(中文版)

这个等待队列是一个CLH锁队列的变体,CLH通常情况下被用来做自旋锁,“我们”改为使用它们来作为实现阻塞同步器,包含线性的(前后)链表,加上一个可以允许在释放锁时候狗后直接点发送一个信号的状态字段,处理相关因为中断超时引起的取消操作,这个状态字段包含位(代码实现时使recheck启用信号和重新检查)可以跟踪一个线程是否需要一个信号,除了这些附加的内容,我们还维护了大多数CLH的本地属性。


CLH的入队操作(英文版)

To enqueue into a CLH lock,you atomically splice it in as new tail. To dequeue, you set the head field,so the next eligible waiter becomes first

CLH的入队操作(中文版)

入队到CLH锁队列时候,自动会将它作为新的队尾节点拼接到队列里面,出队列的时候回设置队首的位置(就是将第一个节点的next指针指向的的节点元素作为队首),也就是下一个等待者成为了队首元素。


CLH的入队操作分析(英文版)

Insertion into a CLH queue requires only a single atomic operation on"tail", so there is a simple point of demarcation from un queued to queued.The"next"link of the predecessor is set by the enqueuing thread after successful CAS.Eventhough non-atomic, this suffices to ensure that any blocked thread is signalled by a predecessor when eligible(although in the case of cancellation, possibly with the assistance of a signal in method clean Queue) .Signalling is based in part on a Dekker-like scheme in which the to-be waiting thread indicates WAITING status, then retries acquiring, and then re checks status before blocking.The signaller atomically clears WAITING status when un parking.

CLH的入队操作分析(中文版)

插入CLH队列需要对队尾节点进行原子操作, 所以有一个简单的入队和出队界定指针,当一个线程CAS成功之后会将自己入队, 设置前一个节点的下一个链接(next) 设置成自己(就是如果一个线程入队成功了, 将前一个节点的next设置成自己)。即使是非原子的这个可以确保任何阻塞的线程在符合条件时(即使在取消的情况下,也可以借助clean Queue方法中的一个信号) 会收到来自前一个节点(node) 的信号, 信号发送部分基于类似De kke的方案, 将要等待的线程表示等待状态,然后重新获取,接下来就是在加锁前重新检测状态。当取消等待(un parking) 的时候,信号发送者会自动清理等待状态。


CLH的出队操作分析(英文版)

Dequeuing on acquire involves detaching(nulling) anode’s “prev"node and then updating the"head”.Other threads check if anode is or was dequeued by checking"prev"rather than head.We enforce the nulling then setting order by spin-waiting if necessary.Because of this, the lock algorithm is not itself strictly"lock-free"because an acquiring thread may need to wait for a previous acquire to make progress.When used with exclusive locks, such progress is required anyway.However Shared mode may(uncommonly) require asp in-wait before setting head field to ensure proper propagation.(Historical note:This allows some simplifications and efficiencies
compared to previous versions of this class.)

CLH的出队操作分析(中文版)

当获取时出队列涉及到了分离(置空)一个节点“prev"节点, 然后更新"head"节点。(其实就是出队列的时候当前节点的prev置空或者分离出去) 。其他的线程需要通过检测"prev"而不是“head"来检测一个节点是否(将要/已经)出队列了(这个地方需要通过检测节点的prev判断是否已经出队列了, 判断head不行, 因为head可能已经出队列了)。如果有必要,我们会强制置空,然后通过自旋等待来设置顺序。因为这个原因,锁算法本身不是严格无锁的,因为一个获取锁的线程可能需要等到上一个获取锁的线程运行。当与排他锁一起使用的时候,像这样的运行无论如何都是必须的。然而在共享模式下可能很罕见)需要一个自旋等待,等待确保前一个进程设置了head字段。


CLH的取消节点任务(英文版)

Anode’s predecessor can change due to cancellation while it is waiting, until the node is first in queue, at which point it
can not change.The acquire method scope with this by rechecking "prev"before waiting.The prev and next fields are modified only via CAS by cancelled nodes in method clean Queue.The un splice strategy is reminiscent of Michael-Scott queues in that after a successful CASto prev field, other threads help fix next fields.Because cancellation often occurs in bunches that complicate decisions about necessary signals, each call to clean Queue traverses the queue until a cleansweep.Nodes that become relinked as first are unconditionally un parked
(sometimes unnecessarily, but those cases are not worth avoiding) .

CLH的取消节点任务(中文版)

一个节点的前一个等待节点,在等待的同时可以被取消操作改变,除非当前节点是队列里面的第一个节点,第一个节点不用变。获取方法在等待之前通过再次检测prev来应对处理(是否要改变上一个节点)。在清空方法队列中的被取消的节点,只能通过CAS操作改变上一个和下一个属性。这个不拼接的策略让人想起Michael-Scott队列, 在这个队列里当对prev字段成功CAS之后,其他的线程帮助修改下一个字段。因为取消操作经常是一大堆一大堆的发生,从而关于必要的信号决策变得很难,每次调用都会对队列遍历,直到清除干净。成为重新链接的节点首先会被无条件的出队列(有时虽然不是必须的,但是这些情况都不值得避免。)


CLH的节点抢占锁(英文版)

A thread may try to acquire if it is first(front most) in the *queue, and sometimes before.Being first does not guarantee *success; it only gives the right to contend.We balance *throughput, overhead, and fairness by allowing incoming threads *to"barge"and acquire the synchronizer while in the process of *enqueuing, in which case an awakened first thread may need to *re wait.To counteract possible repeated unlucky re waits, we *exponentially increase retries(up to 256) to acquire each time *a thread i sun parked.Except in this case, AQS locks do not *spin; they instead interleave attempts to acquire with *bookkeeping steps.(Users who want spinlocks can use *try Acquire.)

CLH的节点抢占锁(中文版)

一个线程如果是队列里面的第一个线程可能会尝试获取锁,第一个线程不能确保成功,在它之前的线程也会去尝试获取锁.它仅仅赋予了竞争的权利。在入队列的过程中,通过允许进来的线程来抢占和获取同步器来平衡吞吐量、开销和公平与否,在这种情况下,一个已经被唤醒的第一个线程可能还会需要重新等待。为了抵消可能出现的反复的不幸的重复等待,我们会在每一次线程出队时,指数的增加重试次数来获取锁。除了这种情况, AQS不自旋。他们反而会交错尝试通过记账步骤来获取锁。(想要自旋锁的用户可以使用try Acquire) .


CLH的GC回收和资源释放(英文版)

To improve garbage collectibility, fields of nodes not yet on list are null.(It is not rare to create and then throwaway a node without using it.) Fields of nodes coming off the list are nulled out as soon as possible.This accentuates the challenge of externally determining the first waiting thread(as in method get First Queued Thread) .This sometimes requires the fallback of traversing backwards from the atomically updated "tail"when fields appear null.(This is never needed in the process of signalling though.)

CLH的GC回收和资源释放(中文版)

为了提高垃圾回收的能力,节点的属性字段还没列出的都先为null(节点创建之后还没有使用就被丢掉是很常见的) 节点的属性字段从list上脱落(不适用的时候) 要尽快置为null.这加剧了从外部确定第一个等待线程的挑战。有时当字段为空的时候,需要从原子更新尾部向后遍历来获得反馈(在处理信号的过程中就从来不需要这个操作).


CLH的GC资源创建及共享和互斥模式(英文版)

CLH queues need a dummy header node to get started.But wed on’t create the mon construction, because it would be wasted effort if there is never contention.Instead, the node is constructed and head and tail pointers are setup on first contention. Shared mode operations differ from Exclusive in that an acquire signals the next waiter to try to acquire if it is also Shared.The try Acquire Shared APl allows users to indicate the degree of propagation, but in most applications, it is more efficient to ignore this, allowing the successor to try acquiring in any case.

CLH的GC资源创建及共享和互斥模式(中文版)

CLH队列不需要从一个假的头节点来开始, 但是我们不在结构上创建,因为如果永远都没有竞争,那么就是白费力气。相反,节点的构造和头尾指针会在第一次竞争时设置好。共享模式操作和排他的操作的区别在于,如果一个获取锁还是共享的话,它会给下一个等待的线程发送信号让它来尝试获取锁。尝试获取共享锁API可以允许用户表明传播程度, 但是在大多数应用程序中允许后者在任何情况下获取锁,会使效率更高。


CLH的资源抢占和授权控制(英文版)

Threads waiting on Conditions use nodes with an additional link to maintain the(FIFO) list of conditions.Conditions only *need to link nodes in simple(non-concurrent) linked queues *because they are only accessed when exclusively held.Upon *await, anode is inserted into a condition queue.Upon signal,*the node is enqueued on the main queue.A special status field *value is used to track and atomically trigger this. Accesses to fields head, tail, and state usefull Volatile mode, along with CAS.Node fields status, prev and next also do *so while threads maybe sign all able, but sometimes use weaker modes otherwise.Accesses to field"waiter"(the thread to be
signalled) are always sandwiched between other atomic accesses so are used in Plain mode.We use jdk.internal Unsafe versions *of atomic access methods rather than Var Handles to avoid
*potential VM bootstrap issues.

CLH的资源抢占和授权控制(中文版)

等待条件的线程使用节点时,需要一个也额外的链表来维护条件链表。条件仅需要使用一个简单的链表队列来链接节点,因为它仅仅实在获取到了排他锁之后才允许访问。(不需要线程安全的,因为是获取到了锁之后才能操作,本身安全) 当调用await方法时, 一个节点被插入到条件队列里,当调用信号方法时,节点会从主要队列中出队列。一个特别的状态字段值被用来跟踪和原子的触发这个条件。(什么条件呢?un park 和park中的那个permits),访问属性字段的头、尾以及状态需要使用完全的Volatile模式一同CAS操作, 当线程可以发信号,节点的状态字段、前后指针也需要Volatile和CAS, 但是有时我们使用较弱的模式。尤其是其他原子访问也是使用普通模式的时候,访问等待线程的字段通常是模棱两可的。我们使用Unsafe 原子访问方法的版本而不使用Var Handles, 为了避免VM启动时出现的潜在的风险。


总结归纳(英文)

Most of the above is performed by primary internal method acquire, that is invoked in some way by all exported acquire methods.(It is usually easy for compilers to optimize
call-site specializations when heavily used.)
There are several arbitrary decisions about when and howto check interrupts in both acquire and await before and/or after blocking.The decisions are less arbitrary in implementation updates because some users appear to relyon original behaviors in ways that are racy and so(rarely) wrong in general but hard to justify changing.
Thanks goto Dave Dice, Mark Moir, Victor Luc hang co, Bill Scherer and Michael Scott, along with members of JSR-166expert group, for helpful ideas, discussions, and critiques on the design of this class.

总结归纳(中文)

上面这些大部分都是通过主要的内部acquire方法来运行,在某种轻度上,所有的暴露出来的获取锁方法都会被调用((过度(频)使用通常让编译器对调用者配置优化变得简单)。上面这些大部分都是通过主要的内部acquire方法来运行,在某种轻度上,所有的暴露出来的获取锁方法都会被调用((过度(频)使用通常让编译器对调用者配置优化变得简单)。

这篇关于(笔者推荐)【Java权威指南】「官方文档-中英互译」AQS的源码注释分析,贯穿总体核心流程!的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/594780

相关文章

python panda库从基础到高级操作分析

《pythonpanda库从基础到高级操作分析》本文介绍了Pandas库的核心功能,包括处理结构化数据的Series和DataFrame数据结构,数据读取、清洗、分组聚合、合并、时间序列分析及大数据... 目录1. Pandas 概述2. 基本操作:数据读取与查看3. 索引操作:精准定位数据4. Group

Spring Boot集成/输出/日志级别控制/持久化开发实践

《SpringBoot集成/输出/日志级别控制/持久化开发实践》SpringBoot默认集成Logback,支持灵活日志级别配置(INFO/DEBUG等),输出包含时间戳、级别、类名等信息,并可通过... 目录一、日志概述1.1、Spring Boot日志简介1.2、日志框架与默认配置1.3、日志的核心作用

破茧 JDBC:MyBatis 在 Spring Boot 中的轻量实践指南

《破茧JDBC:MyBatis在SpringBoot中的轻量实践指南》MyBatis是持久层框架,简化JDBC开发,通过接口+XML/注解实现数据访问,动态代理生成实现类,支持增删改查及参数... 目录一、什么是 MyBATis二、 MyBatis 入门2.1、创建项目2.2、配置数据库连接字符串2.3、入

Springboot项目启动失败提示找不到dao类的解决

《Springboot项目启动失败提示找不到dao类的解决》SpringBoot启动失败,因ProductServiceImpl未正确注入ProductDao,原因:Dao未注册为Bean,解决:在启... 目录错误描述原因解决方法总结***************************APPLICA编

深度解析Spring Security 中的 SecurityFilterChain核心功能

《深度解析SpringSecurity中的SecurityFilterChain核心功能》SecurityFilterChain通过组件化配置、类型安全路径匹配、多链协同三大特性,重构了Spri... 目录Spring Security 中的SecurityFilterChain深度解析一、Security

MySQL中EXISTS与IN用法使用与对比分析

《MySQL中EXISTS与IN用法使用与对比分析》在MySQL中,EXISTS和IN都用于子查询中根据另一个查询的结果来过滤主查询的记录,本文将基于工作原理、效率和应用场景进行全面对比... 目录一、基本用法详解1. IN 运算符2. EXISTS 运算符二、EXISTS 与 IN 的选择策略三、性能对比

SpringBoot多环境配置数据读取方式

《SpringBoot多环境配置数据读取方式》SpringBoot通过环境隔离机制,支持properties/yaml/yml多格式配置,结合@Value、Environment和@Configura... 目录一、多环境配置的核心思路二、3种配置文件格式详解2.1 properties格式(传统格式)1.

Apache Ignite 与 Spring Boot 集成详细指南

《ApacheIgnite与SpringBoot集成详细指南》ApacheIgnite官方指南详解如何通过SpringBootStarter扩展实现自动配置,支持厚/轻客户端模式,简化Ign... 目录 一、背景:为什么需要这个集成? 二、两种集成方式(对应两种客户端模型) 三、方式一:自动配置 Thick

SQL Server跟踪自动统计信息更新实战指南

《SQLServer跟踪自动统计信息更新实战指南》本文详解SQLServer自动统计信息更新的跟踪方法,推荐使用扩展事件实时捕获更新操作及详细信息,同时结合系统视图快速检查统计信息状态,重点强调修... 目录SQL Server 如何跟踪自动统计信息更新:深入解析与实战指南 核心跟踪方法1️⃣ 利用系统目录

使用IDEA部署Docker应用指南分享

《使用IDEA部署Docker应用指南分享》本文介绍了使用IDEA部署Docker应用的四步流程:创建Dockerfile、配置IDEADocker连接、设置运行调试环境、构建运行镜像,并强调需准备本... 目录一、创建 dockerfile 配置文件二、配置 IDEA 的 Docker 连接三、配置 Do