aqs

    科技2024-07-25  17

    aqs

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

    概念

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

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

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

    接口

    Lock接口,api

    locktrylockunlock

    实现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

    Processed: 0.036, SQL: 8