aqs

AQS(抽象队列同步器)是Java中实现锁和同步器的基础框架,用于创建自定义同步组件。它基于CAS(Compare and Swap)和volatile实现线程间的同步,避免了锁的互斥。AQS维护了一个内部的等待队列,当线程尝试获取锁失败时,会被构造成节点加入队列并被阻塞。公平锁和非公平锁两种策略用于控制锁的分配。释放锁时,AQS会唤醒队列中的后续节点。整个过程确保了线程安全和高效并发。
摘要由CSDN通过智能技术生成

aqs

AQS(abstract queue synchronizer).为什么底层是cas+volatile

概念

aqs是一个框架,用来提供一种阻塞锁和一系列依赖等待队列的同步器框架比如reentrantlock,countdownlatch

使用方法是继承aqs并实现它的模版方法然后讲子类作为组件的内部类

是java自带的 synchronized以外的锁机制

接口

Lock接口,api

  • lock
  • trylock
  • unlock

实现lock接口的有很多类,比如reentrantlock,readwritelock等

问题

由于这些lock锁机制不是使用syn关键字实现的,那么如何使用竞争锁呢?

结构

它本身没有实现任何同步的接口,只定义了同步状态的获取以及释放来提供自定义同步

aqs的功能分为独占以及共享.

aqs的同步功能依赖内部的队列Node类型(双向链表)

fairsync(公平锁.所有线程严格按照fifo获取锁),nofairsync(非公平锁,新线程也有机会抢锁),

队列:

aqs维护了一个队列,队列的第一位是当前占用线程,后面几位是等待线程,如果当前线程竞争锁失败则将当前线程保存到node中再阻塞该线程当获取锁的线程释放锁后,再从节点中唤醒一个阻塞的节点.

队列里出队入队都用cas操作,因为有一堆线程来加node尾巴

源码解析

reentrantlock首先调用lock方法尝试获取锁,此处为多线程调用,内部实现为cas操作,其他线程都尝试获取锁,但是其中有一条线程一定是获取了锁的

        final void lock() {
            if (compareAndSetState(0, 1))//cas操作
                setExclusiveOwnerThread(Thread.currentThread());//设置当前获取锁的线程
            else
                acquire(1);//继续尝试获取锁
        }
//尝试获取锁   
public final void acquire(int arg) {
  //如果未获取到锁
        if (!tryAcquire(arg) &&
            //将当前线程封装进node中
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

使用cas操作对state赋值

    /**
     * The synchronization state.
     */
    private volatile int state;//设置成volatile线程间可见
  • 当state=0时(默认)无锁
  • 当state>0时有线程获取了锁,重入锁允许设置多个锁,于是state会递增,释放锁时也需要释放多次让state变为0
  • 不同的aqs实现(锁),state表达的含义也是不一样的

nofairtryAcquire

非公平锁尝试获取锁状态,获取当前线程,获取state的状态,修改state状态为1

addwaiter

当tryAcquire失败后,调用addwaiter方法(new Node)封装,当前Thread,与node属性,设置到等待队列中

enq

enq内部通过自旋的方式将node节点设置进队列中

acquireQueued

此方法内做抢占锁的操作.只有prev节点为head的节点才有机会抢占锁(tryAcquire,否则就挂起线程)

shouldparkAfterFailedAcquire

内部进行判断是否需要挂起线程,修改节点的链接状态(前置节点 后置节点)

parkAndCheckInterrupt

通过LockSupport.park方法将当前线程挂起到waiting状态,LockSupport使用了线程原语native方法,unsafe里的函数

锁的释放

    public final boolean release(int arg) {
      //尝试释放锁
        if (tryRelease(arg)) {
          //如果有其他的头节点
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }
        protected final boolean tryRelease(int releases) {
          //减去重入锁的次数
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
          //如果重入次数为0
            if (c == 0) {
                free = true;
              //设置当前独占锁为null
          
                setExclusiveOwnerThread(null);
            }
          //设置锁状态为0,无锁
            setState(c);
            return free;
        }
    private void unparkSuccessor(Node node) {
        /*
         * If status is negative (i.e., possibly needing signal) try
         * to clear in anticipation of signalling.  It is OK if this
         * fails or if status is changed by waiting thread.
         */
        int ws = node.waitStatus;
        if (ws < 0)
            compareAndSetWaitStatus(node, ws, 0);

        /*
         * Thread to unpark is held in successor, which is normally
         * just the next node.  But if cancelled or apparently null,
         * traverse backwards from tail to find the actual
         * non-cancelled successor.
         */
        Node s = node.next;
        if (s == null || s.waitStatus > 0) {
            s = null;
            for (Node t = tail; t != null && t != node; t = t.prev)
                if (t.waitStatus <= 0)
                    s = t;
        }
        if (s != null)
          //释放节点
            LockSupport.unpark(s.thread);
    }

解释aqs,要解释cas volatile

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值