当前位置: 首页 > article >正文

AQS 理解 及不可重入锁实现

由于目前水平有限,只是写出作者目前对 aqs的简单理解,有错误还请评论指证

AQS是什么

Aqs是java.util.concurrent 包下的一个抽象队列 同步器类,被简写为英文AQS,

我认为 可以把他理解 为一个 实现 自定义 锁的 一个具体的框架 ,我们可以根据这个 框架来实现出 自己的锁, 比如我们经常用到的  ReentrantLock,线程池  等 其他需要锁的类 内部类都实现了

AQS也就是 AbstractQueuedSynchronizer  

AQS解释

 AQS类的内部 是怎么来实现  原子性呢?  就是用Unsafe 来进行的, 

它的内部 维护了一个共享的变量 state ,  当satae 为0的时候,代表 没有被 其他线程 抢占到,如果state 为1

就代表 被其他线程抢占到了  这时候 其他线程会进入fifo 队列中等待

这么说太抽象了,我们直接上代码 来简单理解作者目前认为的 AQS

代码实现

首先 我们有一个 类 来继承了 AQS

final class Sync extends AbstractQueuedSynchronizer {
    @Override
    protected boolean tryAcquire(int arg) {
        //在 自定义锁中的lock方法去尝试给线程上锁的时候
        //根据传入的 arg 表示 来修改 AbstractQueuedSynchronizer类内部 的state 表示 进行上锁
        if (arg == 1) {//代表 要执行的是上锁操作
            if (compareAndSetState(0, 1)) {//原来0 是 锁未被其他线程使用
                // 修改为1 代表 上锁成功
                setExclusiveOwnerThread(Thread.currentThread());//设置 拥有锁的线程为 当前线程
                System.out.println(6666666);
                return true;
            }
        }
        return false;
    }

    @Override
    protected boolean tryRelease(int arg) {
        if (arg == 1) { //代表执行的是解锁操作
            if (getState() == 0) {//当前线程 进行解锁操作 发现 锁 并未被占用 所以抛出异常
                throw new IllegalMonitorStateException();
            }
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }
        return false;
    }

    @Override
    protected boolean isHeldExclusively() {//看当前线程是否 被占用
        return getState() == 1;
    }

    protected Condition newCondition() {
        return new ConditionObject();
    }
}

然后 我们 有一个自定义的锁 类, 内部 有一个该 Sync类的实现,通过操作 我们重写的AQS类的部分逻辑 来进行 加锁 操作

//不可重入锁
class MyLock implements Lock {

    static Sync sync = new Sync();

    @Override
    public void lock() {//不成功 进入等待队列
        sync.acquire(1);
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {//可打断 不成功进入等待队列
        sync.acquireInterruptibly(1);
    }

    @Override
    public boolean tryLock() {//尝试上锁 立即返回
        return sync.tryAcquire(1);
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireNanos(1, TimeUnit.SECONDS.toNanos(1));
    }

    @Override
    public void unlock() {
        sync.release(1);
    }

    @Override
    public Condition newCondition() {
        return sync.newCondition();
    }
}

看完这些代码 可能 有人会有疑惑,为什么 这个自定义的锁类,中调用的sync的方法 有的在 上面自定义的Sync类中没有,因为 我们调用的是其父类AQS的方法,我们目前自定义的sync类中的方法 就是 简单来模拟 一些AQS内部主要的加锁解锁的方法

我们再看 测试类

public class AqsTest {
    public static void main(String[] args) {
        MyLock myLock = new MyLock();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    myLock.lock();
                    System.out.println("上锁了t1");
                    sleep(1000);
//                   myLock.lock();
//                   System.out.println("上锁了t1重入");
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                } finally {
                    System.out.println("解锁了t1");
                    myLock.unlock();
                }
            }
        }, "t1").start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("线程t2尝试获得锁");
                    myLock.lock();
                    System.out.println("上锁了t2");
                } finally {
                    System.out.println("解锁了t2");
                    myLock.unlock();
                }
            }
        }, "t2").start();
    }
}

代码分析

我们运行出来结果为

我们有的可能看到上面的代码实现就懵逼了,现在我们现在来看代码,稍微解读一下

首先 我们的 t1线程调用了 自定义锁的lock方法,开始去上锁

然后 到 自定义的 lock方法内部 去调用 sync 的acquire方法,我们点进去看acquire方法的实现

在aqs类内部,首先判断 这个线程是否获得锁,而这个 tryAcquire方法 走的逻辑 就是我们前面 重写的方法逻辑,先判断是否为上锁操作,然后用cas修改sate的状态值,然后设置 锁的拥有线程为当前线程,然后返回true,这时候 t2线程进来的话,t1线程由于没有释放锁tryacquire必然是false,这时候 就会走 aqs内部的acquire的方法,来进入等待队列

这时候 我们可能就对 aqs 有了一点点的理解,现在 我们再来看  ReentrantLock的源码实现,发现 好像用的是类似的逻辑

 总之 我目前认为aqs 就是 一个功能强大 锁实现框架


http://www.kler.cn/a/404649.html

相关文章:

  • Nacos实现IP动态黑白名单过滤
  • ant-design-vue中table组件多列排序
  • 结合第三方模块requests,文件IO、正则表达式,通过函数封装爬虫应用采集数据
  • 手机领夹麦克风哪个牌子好,哪种领夹麦性价比高,热门麦克风推荐
  • Tcp协议Socket编程
  • HTML5实现剪刀石头布小游戏(附源码)
  • C++:operator new/delete函数
  • 前端面试之九阴真经
  • 金融量化交易领域,许多开源平台提供了图形用户界面(GUI)
  • Java-异常处理机制-throws
  • 【PCIE常见面试问题-1】
  • SpringBoot(三十三)SpringBoot集成Spring boot actuator程序监控器
  • 如何查找 Kafka消息队列中主题Topic的消费者?
  • C#高级:通过反射判断列表中指定字段是否存在空值
  • 笔记记录 k8s-RBAC
  • MySQL最后练习,转转好物交易平台项目
  • wpf中几种获取ComBox中值的方法
  • 机器学习基础06_梯度下降
  • 基于Java Springboot导师选择管理系统
  • Palo Alto Networks PAN-OS身份认证绕过导致RCE漏洞复现(CVE-2024-0012)
  • 【golang-技巧】- context 使用
  • spacy 安装 en_core_web_sm
  • MySQL中有哪几种锁?
  • Linux基础指令(汇总)
  • StarRocks 架构
  • Flutter:AnimatedPadding动态修改padding