java AQS(AbstractQueuedSynchronizer) 简单用法实现 ✨ 每日积累

简介: java AQS(AbstractQueuedSynchronizer) 简单用法实现 ✨ 每日积累

AQS是什么


api中如下描述:

提供一个框架,用于实现依赖先进先出(FIFO)等待队列的阻塞锁和相关同步器(信号量,事件等)。该类被设计为大多数类型的同步器的有用依据,这些同步器依赖于单个原子int值来表示状态。子类必须定义改变此状态的受保护方法,以及根据该对象被获取或释放来定义该状态的含义。给定这些,这个类中的其他方法执行所有排队和阻塞机制。子类可以保持其他状态字段,但只以原子方式更新int使用方法操纵值getState() , setState(int)和compareAndSetState(int, int)被跟踪相对于同步。


子类应定义为非公共内部助手类,用于实现其封闭类的同步属性。 AbstractQueuedSynchronizer类不实现任何同步接口。 相反,它定义了一些方法,如acquireInterruptibly(int) ,可以通过具体的锁和相关同步器来调用适当履行其公共方法。


此类支持默认独占模式和共享模式。 当以独占模式获取时,尝试通过其他线程获取不能成功。 多线程获取的共享模式可能(但不需要)成功。 除了在机械意义上,这个类不理解这些差异,当共享模式获取成功时,下一个等待线程(如果存在)也必须确定它是否也可以获取。 在不同模式下等待的线程共享相同的FIFO队列。 通常,实现子类只支持这些模式之一,但是两者都可以在ReadWriteLock中发挥作用 。 仅支持独占或仅共享模式的子类不需要定义支持未使用模式的方法。


这个类定义的嵌套AbstractQueuedSynchronizer.ConditionObject可用于作为一类Condition由子类支持独占模式用于该方法的实施isHeldExclusively()份报告是否同步排他相对于保持在当前线程,方法release(int)与当前调用getState()值完全释放此目的,和acquire(int) ,给定此保存的状态值,最终将此对象恢复到其先前获取的状态。 AbstractQueuedSynchronizer方法将创建此类条件,因此如果不能满足此约束,请勿使用该约束。 AbstractQueuedSynchronizer.ConditionObject的行为当然取决于其同步器实现的语义。


该类为内部队列提供检查,检测和监控方法,以及条件对象的类似方法。 这些可以根据需要导出到类中,使用AbstractQueuedSynchronizer进行同步机制。


此类的序列化仅存储底层原子整数维持状态,因此反序列化对象具有空线程队列。 需要可序列化的典型子类将定义一个readObject方法,可以将其恢复为readObject时的已知初始状态。


用法

使用这个类用作同步的基础上,重新定义以下方法,如适用,通过检查和/或修改使用所述同步状态getState() , setState(int)和/或compareAndSetState(int, int) :


tryAcquire(int)

tryRelease(int)

tryAcquireShared(int)

tryReleaseShared(int)

isHeldExclusively()

每个这些方法默认抛出UnsupportedOperationException 。这些方法的实现必须是线程安全的,通常应该是短的而不是阻止的。定义这些方法是唯一支持使用此类的方法。所有其他方法都被声明为final ,因为它们不能独立变化。


您还可以找到来自继承的方法AbstractOwnableSynchronizer有用跟踪线程拥有独家同步的。 我们鼓励您使用它们 - 这样可以使监控和诊断工具帮助用户确定哪些线程持有锁定。


简单实现

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
public class AQSLockTest implements Lock {
    private Sync sync = new Sync();
    @Override
    public void lock() {
        sync.acquire(1);
    }
    @Override
    public void lockInterruptibly() throws InterruptedException {
    }
    @Override
    public boolean tryLock() {
        return false;
    }
    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return false;
    }
    @Override
    public void unlock() {
        sync.release(1);
    }
    @Override
    public Condition newCondition() {
        return null;
    }
    private class Sync extends AbstractQueuedSynchronizer{
        @Override
        protected boolean tryAcquire(int arg) {
            //只有传入才可以正常执行
            assert arg == 1;
            //CAS操作将,满足预期值为0,将当前State设置为1之后线程独占此锁
            if (compareAndSetState(0, 1)){
                //线程独占锁
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }
        @Override
        protected boolean tryRelease(int arg) {
            assert arg == 1;
            if (!isHeldExclusively()) throw new IllegalMonitorStateException();
            //拿锁的线程才可以释放锁,将state改为0
            setState(0);
            return true;
        }
        @Override
        protected boolean isHeldExclusively() {
          //判断当前是否持有独占锁
            return getExclusiveOwnerThread() == Thread.currentThread();
        }
    }
}
相关文章
|
1天前
|
Java
Java中的抽象类:深入了解抽象类的概念和用法
Java中的抽象类是一种不能实例化的特殊类,常作为其他类的父类模板,定义子类行为和属性。抽象类包含抽象方法(无实现)和非抽象方法。定义抽象类用`abstract`关键字,子类继承并实现抽象方法。抽象类适用于定义通用模板、复用代码和强制子类实现特定方法。优点是提供抽象模板和代码复用,缺点是限制继承灵活性和增加类复杂性。与接口相比,抽象类可包含成员变量和单继承。使用时注意设计合理的抽象类结构,谨慎使用抽象方法,并遵循命名规范。抽象类是提高代码质量的重要工具。
40 1
|
1天前
|
前端开发 Java
java中的Queue队列的用法
java中的Queue队列的用法
21 1
|
1天前
|
XML Java 编译器
java aspectjrt AOP 用法
java aspectjrt AOP 用法
28 0
|
1天前
|
Java
Java中return的两种用法
Java中return的两种用法
|
1天前
|
SQL Java
【JAVA进阶篇教学】第九篇:MyBatis-Plus用法介绍
【JAVA进阶篇教学】第九篇:MyBatis-Plus用法介绍
|
1天前
|
Java API 调度
【Java多线程】Thread类的基本用法
【Java多线程】Thread类的基本用法
8 0
|
1天前
|
存储 Java
java IO接口(Input)用法
【5月更文挑战第1天】Java的`java.io`包包含多种输入输出类。此示例展示了如何使用`FileInputStream`从`input.txt`读取数据。首先创建`FileInputStream`对象,接着创建一个字节数组存储读取的数据,调用`read()`方法将文件内容填充至数组。然后将字节数组转换为字符串并打印,最后关闭输入流。注意,`InputStream`是抽象类,此处使用其子类`FileInputStream`。其他子类如`ByteArrayInputStream`、`ObjectInputStream`和`BufferedInputStream`各有特定用途。
22 2
|
1天前
|
Java
java lambda 表达式中的双冒号和箭头的用法
java lambda 表达式中的双冒号和箭头的用法
|
1天前
|
Java
java中break和continue的用法例子
java中break和continue的用法例子