ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

【JUC 并发编程】— AQS 概述与实例

2022-06-08 18:36:46  阅读:236  来源: 互联网

标签:JUC 同步 AQS int 编程 boolean 同步器 protected arg


介绍

队列同步器 AbstractQueuedSynchronizer,简称为 AQS,是用来构建锁及其他同步组件(比如 ReentrantLock、CountDownLatch)的基础框架。它使用了一个 int 成员变量表示同步状态,通过内置的 FIFO 队列来完成获取资源线程的排队工作。AQS 的主要使用方式是继承,子类被推荐被定义为自定义同步组件的静态内部类,通过实现同步器的一些protected方法。 如果一个类想成为状态依赖的类,那么它必须拥有一些状态。AQS 负责管理同步器类的状态,可以通过 getState、setState 以及 compareAndSetState 等 protected 类型方法来进行操作。

如果某个同步器支持独占式操作,那么需要实现一些 protected 方法,包括 tryAcquire、tryRelease 和 isHeldExclusively 等;而对于支持共享获取的同步器,则应该实现 tryAcquireShared 和 tryReleaseShared 等方法。

AQS 是实现锁(也可以是任意同步组件)的关键,在锁的实现中聚合同步器,利用同步器实现锁的语义。可以这样理解二者之间的关系:

琐是面向使用者的,它定义了使用者与锁交互的接口,隐藏了实现细节;同步器面向锁的,它简化了锁的实现方式,屏蔽了同步状态的管理、线程的排队、等待与唤醒等底层操作。锁和同步器很好的隔离了使用者和实现者所需关注的领域。

接口

同步器的设计设计是基于模板方式模式的,也就是说,使用者需要继承同步器并重写指定的方法。

同步状态相关方法

重写同步器指定的方法时,需要使用到同步器提供的一下三个方法来访问或修改同步状态:


/**
 * 获取同步状态
 * Returns the current value of synchronization state.
 *
 * 这个操作有 volatile 读的内存语义,也就是说总是从主内存获取,保证同步状态是最新的
 * This operation has memory semantics of a <tt>volatile</tt> read.
 * @return current state value
 */
protected final int getState() {
    return state;
}

/**
 * 设置同步状态
 * Sets the value of synchronization state.
 *
 * 这个操作有 volatile 写的内存语义,也就是写完就同步到主内存
 * This operation has memory semantics of a <tt>volatile</tt> write.
 * @param newState the new state value
 */
protected final void setState(int newState) {
    state = newState;
}

/**
 * CAS 方式设置状态,有 volatile 的读写内存语义
 * Atomically sets synchronization state to the given updated
 * value if the current state value equals the expected value.
 * This operation has memory semantics of a <tt>volatile</tt> read
 * and write.
 */
protected final boolean compareAndSetState(int expect, int update) {
    // See below for intrinsics setup to support this
    return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}

可重写方法

自定义同步组件内部静态类(推荐使用)需重写同步器 protected 方法如下:

方法名称 描述
protected boolean tryAcquire(int arg) 独占式获取同步状态,实现该方法需要判断当前的同步状态是否符合预期,然后再 CAS 设置同步状态
protected boolean tryRelease(int arg) 独占式释放同步状态
protected int tryAcquireShared(int arg) 共享式获取同步状态,返回 >=0 的值,表去获取成功,反之失败
protected int tryReleaseShared(int arg) 共享式释放不同状态
protected boolean isHeldExclusively() 当前同步器在独占式模式下是否被占用

模板方法

自定义同步组件时,将会调用同步器的模板方法,如下:

独占式

方法名称 描述
void acquire(int arg) 独占式获取同步状态,不响应中断
void acquireInterruptibly(int arg) 与 acquire(int arg) 相同,但响应中断
boolean tryAcquireNanos(int arg, long nanosTimeout) 在 acquireInterruptibly(int arg) 基础上增加超时限制
boolean release(int arg) 独占式释放同步状态

共享式

方法名称 描述
void acquireShared(int arg) 共享式获取
void acquireSharedInterruptibly(int arg) 与 acquireShared(int arg) 相同,响应中断
boolean tryAcquireSharedNanos(int arg, long nanosTimeout) 在 acquireSharedInterruptibly(int arg) 基础上增加超时限制
boolean releaseShared(int arg) 共享式释放

等待队列信息

方法名称 描述
Collection getQueuedThreads() 获取等待在同步队列上的线程集合

实例

下面代码是独占锁的简单实现


/**
 * 通过 AQS 自定义同步组件
 *
 * @author LBG - 2017/11/8 0008
 */
public class Mutex {

    private final Sync sync = new Sync();

    public void lock() {
        sync.acquire(1);
    }

    public boolean tryLock() {
        return sync.tryAcquire(1);
    }

    /**
     * 限时获取,可中断
     */
    public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }

    public boolean unlock() {
        return sync.release(1);
    }

    public boolean isLocked() {
        return sync.isHeldExclusively();
    }

    public void lockInterruptible() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

    /**
     * 静态内部类,继承同步器
     */
    private class Sync extends AbstractQueuedSynchronizer {

        /**
         * 当状态为0 时获取锁,并把状态改为1
         */
        @Override
        protected boolean tryAcquire(int arg) {
            if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        /**
         * 释放锁,将状态设为0
         */
        @Override
        protected boolean tryRelease(int arg) {
            if (getState() == 0) {
                throw new IllegalMonitorStateException();
            }
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }

        /**
         * 是否处于独占状态,1 表示独占
         */
        @Override
        protected boolean isHeldExclusively() {
            return getState() ==1;
        }
    }
}


本篇主要是对 AQS 有个基本的了解,以及主要方法的作用和使用,接下来则按独占式和共享式分别对其源码进行分析。


参考资料:

标签:JUC,同步,AQS,int,编程,boolean,同步器,protected,arg
来源: https://www.cnblogs.com/tailife/p/16356731.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有