如何深入理解Java多线程与并发框中的队列同步器AQS,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。
一、 AbstractOwnableSynchronizer 抽象的、可拥有的同步器
源码分析:
package java.util.concurrent.locks; /** * 可由线程独占的同步器。 * 该类为创建锁和相关的同步器提供了基础,可能需要拥有所有权的概念。 * AbstractOwnableSynchronizer 类本身不管理或使用此信息。 * 但是,子类和工具可以使用适当维护的值来帮助控制和监视访问并提供诊断。 * * @since 1.6 * @author Doug Lea */ public abstract class AbstractOwnableSynchronizer implements java.io.Serializable { /** 即使所有的字段都是短暂的(被禁止序列化的),也要使用 序列ID。*/ private static final long serialVersionUID = 3737899427754241961L; /** * 供子类使用的空的构造方法。 */ protected AbstractOwnableSynchronizer() { } /** * 独占模式同步下的当前(线程)拥有者。(也就是当前独占锁的线程) */ private transient Thread exclusiveOwnerThread; /** * 设置 当前拥有独占访问的 线程。 * 空参数指示没有线程拥有访问权限。 * 此方法不另外施加任何同步化易失性 volatile 字段访问。 * @param thread 所有者的线程(拥有当前独占访问权的线程) */ protected final void setExclusiveOwnerThread(Thread thread) { exclusiveOwnerThread = thread; } /** * 返回 setExclusiveOwnableThread(Thread thread) 方法最后设置的线程, * 如果从未设置,则返回 null。 * 此方法不另外施加任何同步化易失性 volatile 字段访问。 * @return 所有者的线程(拥有当前独占访问权的线程) */ protected final Thread getExclusiveOwnerThread() { return exclusiveOwnerThread; } }
小结: 独占、持有锁的线程成员变量:Thread exclusiveOwnerThread setExclusiveOwnerThread(Thread thread) 设置独占、持有锁的线程成员变量 getExclusiveOwnerThread() 获得独占、持有锁的线程成员变量
AbstractQueuedSynchronizer 简介
提供了一个基于 FIFO队列,可以用于构建锁或者其他相关同步装置的基础框架。该 抽象队列同步器(以下简称队列同步器)利用了一个 private volatile int state来表示 同步状态,期望它能够成为实现大部分同步需求的基础。使用的方法是继承,子类通过继承同步器并需要实现它的方法来管理其状态,管理的方式就是通过类似 acquire获取 和 release释放 的方式来 操纵状态。然而 多线程环境中对状态的操纵必须确保原子性,因此子类对于状态的把握,需要使用这个同步器提供的以下三个方法对状态进行操作:
private volatile int state;
java.util.concurrent.locks.AbstractQueuedSynchronizer.getState()
java.util.concurrent.locks.AbstractQueuedSynchronizer.setState(int newState)
java.util.concurrent.locks.AbstractQueuedSynchronizer.compareAndSetState(int expect, int update)
1. 源码分析:
/** * 返回同步状态的当前值。 * 此操作具有易失性 volatile 读取的内存语义。 * @return 当前 state 的值 */ protected final int getState() { return state; } // ------------------- 华丽的分割线 ------------------- /** * 设置同步状态 state 的值。 * 此操作具有易失性 volatile 写的内存语义。 * @param newState 状态 state 的新值 */ protected final void setState(int newState) { state = newState; } // ------------------- 华丽的分割线 ------------------- /** * 如果当前状态值等于预期值,则以原子方式将同步状态设置为给定的更新值。 * 此操作具有易失性 volatile 读取和写入的内存语义。 * * @param expect 期望的值 * @param update 新值 * @return 如果成功则为 true 。 错误返回表示实际值不等于预期值的指示。 */ protected final Boolean compareAndSetState(int expect, int update) { // See below for intrinsics setup to support this return unsafe.compareAndSwapint(this, stateOffset, expect, update); }
2. FIFO 队列 (类似双向链表)
同步器的开始提到了其实现依赖于一个 FIFO 队列,那么队列中的 元素节点Node 就是保存着 线程引用 和 线程状态 的 容器,每个线程对同步器的访问,都可以看做是队列中的一个节点Node。Node的主要包含以下成员变量:
static final class Node { /** 作为标记表示节点正在 共享模式 中等待 */ static final Node SHARED = new Node(); /** 作为标记表示节点正在 独占模式 下等待 */ static final Node EXCLUSIVE = null; int waitStatus; volatile Node prev; volatile Node next; volatile Thread thread; volatile Node nextWaiter; final Boolean isShared() { return nextWaiter == SHARED; } }
关于如何深入理解Java多线程与并发框中的队列同步器AQS问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注亿速云行业资讯频道了解更多相关知识。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。