AQS 原理分析

点击跳转我的个人知识【原文】

点击去看看个人需求(比如低价【5折】耐克、阿迪达斯等轻奢品)

一. AQS是什么
队列同步器AbstractQueuedSynchronizer(简称为AQS),是用来构建锁或者其他同步组件的基础框架,通过内置的FIFO(先来先服务)队列来完成资源获取线程的排队工作。AQS是实现锁的关键,简单理解两者的关系就是:锁是面向使用者的;AQS面向的是锁的实现者,简化了锁的实现方式,屏蔽了同步状态管理,线程排队,等待唤醒底层操作的细节,对外放出模板方法供子类实现。

本质是通过java 语言自己实现的锁机制,通过一个状态标志+线程阻塞原语实现的锁。
————————————————

二、原理

state =0 资源空闲。>0 资源被占用。

node= 线程抽象。aqs中node 就是线程,将node 串起来==用双向链表实现一个CLH队列。

————————————————

核心方法:

//返回同步状态的当前值
protected final int getState() {
        return state;
}
 // 设置同步状态的值
protected final void setState(int newState) {
        state = newState;
}
//原子地(CAS操作)将同步状态值设置为给定值update如果当前同步状态的值等于expect(期望值)
protected final boolean compareAndSetState(int expect, int update) {
        return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
————————————————

isHeldExclusively()//该线程是否正在独占资源。只有用到condition才需要去实现它。
tryAcquire(int)//独占方式。尝试获取资源,成功则返回true,失败则返回false。
tryRelease(int)//独占方式。尝试释放资源,成功则返回true,失败则返回false。
tryAcquireShared(int)//共享方式。尝试获取资源。负数表示失败;0表示成功,但没有剩余可用资源;正数表示成功,且有剩余资源。
tryReleaseShared(int)//共享方式。尝试释放资源,成功则返回true,失败则返回false。
————————————————

——————进入方法解析——————————

final void lock() {
	//cas操作设置state的值,如果state为0,则说明当前共享资源没有线程占用,设置为1,成功后设置独占线程为当前线程。
     if (compareAndSetState(0, 1))
         setExclusiveOwnerThread(Thread.currentThread());
     else
     //如果state不为0,则说明有线程独占了,进入AQS核心方法,上图可见,随后进入tryAcquire方法
         acquire(1);
}
    /**
     * Acquires in exclusive mode, ignoring interrupts.  Implemented
     * by invoking at least once {@link #tryAcquire},
     * returning on success.  Otherwise the thread is queued, possibly
     * repeatedly blocking and unblocking, invoking {@link
     * #tryAcquire} until success.  This method can be used
     * to implement method {@link Lock#lock}.
     *
     * @param arg the acquire argument.  This value is conveyed to
     *        {@link #tryAcquire} but is otherwise uninterpreted and
     *        can represent anything you like.
     */
    public final void acquire(int arg) {
        //==判断1、是否为重入锁 !tryAcquire(arg)
        // 2、不是重入锁 进行等待 acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))

            //进行线程中断
            selfInterrupt();
    }



//这是子类具体实现方法实现锁的逻辑,进入nonfairTryAcquire方法
protected final boolean tryAcquire(int acquires) {
    return nonfairTryAcquire(acquires);
}

//acquires = 1
final boolean nonfairTryAcquire(int acquires) {
	//==这里又判断是否有资源
    //获取当前线程
    final Thread current = Thread.currentThread();
    //获取state状态
    int c = getState();
    //如果状态为0,跟之前一样,则进入cas设置,并将独占线程设置为自己,返回true
    if (c == 0) {
        if (compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    }


    //==如果state不为0,且当前线程为独占线程,进行+1,也就是重入锁的实现。
    else if (current == getExclusiveOwnerThread()) {
        int nextc = c + acquires;
        if (nextc < 0) // overflow
            throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
    }
    //如果都不满足,表示既有独占线程,当前线程又不是独占线程,则要进入同步队列,等待锁的释放。这一步完进入AQS核心代码也就是第一个图
    return false;
}


private Node addWaiter(Node mode) {
	//将当前线程封装成Node节点。
   Node node = new Node(Thread.currentThread(), mode);
   // 尾交操作--
   Node pred = tail;
   if (pred != null) {
       node.prev = pred;
       if (compareAndSetTail(pred, node)) {
           pred.next = node;
           return node;
       }
   }
   //如果是第一个节点,则进入enq方法
   enq(node);
   return node;
}

private Node enq(final Node node) {
	//通过自旋的方式
	//为啥用循环,cas操作的时候 可能会失败,自旋下
    for (;;) {
        Node t = tail;
        if (t == null) { // Must initialize
            if (compareAndSetHead(new Node()))
                tail = head;
        } else {
            node.prev = t;
            if (compareAndSetTail(t, node)) {
                t.next = node;
                return t;
            }
        }
    }
}

//这里用了 阻塞原语 进行 对线程阻塞  parkAndCheckInterrupt()
final boolean acquireQueued(final Node node, int arg) {
//标记是否成功拿到资源
    boolean failed = true;
    try {
    //标记等待过程是否被中断
        boolean interrupted = false;
        //看到死循环就想到自旋
        for (;;) {
        //获取node的前序节点,这里目前是哨兵节点
            final Node p = node.predecessor();
            //如果前序节点是哨兵节点,则表示你是第二个,老二了,然后这里在尝试获取一次锁,如果成功
            if (p == head && tryAcquire(arg)) {
            //则将当前线程节点设置为哨兵节点
                setHead(node);
                //将之前的哨兵节点置成垃圾,方便gc
                p.next = null; // help GC
                //标识成功获取到资源
                failed = false;
                //表示线程未被中断
                return interrupted;
            }
            //shouldParkAfterFailedAcquire方法判断线程是否需要等待,如果需要则返回true
            //parkAndCheckInterrupt方法进行unsafe.park
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                //都满足后将状态设置为true,也就是中断线程
                interrupted = true;
        }
    } finally {
    //如果节点得不到资源,timeout了则进行中断资源的获取
        if (failed)
            cancelAcquire(node);
    }
}


 

————————————————

解锁

public void unlock() {
//进入release方法
   sync.release(1);
}

//AQS独占锁解锁核心代码
public final boolean release(int arg) {
//进入子类实现的解锁逻辑
//如果tryRelease返回true说明没有独占锁,否则好友线程持有
    if (tryRelease(arg)) {
    //当线程没有持有锁后,唤醒下一个线程执行
        Node h = head;
        //根据waitstatus判断需要唤醒哪个线程
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }
    return false;
} 	


//子类定义的解锁逻辑
protected final boolean tryRelease(int releases) {
//获取state - 1
    int c = getState() - releases;
    //判断当前线程是否是独占资源的线程
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
        //设置资源是否还被独占着
    boolean free = false;
    //如果state = 0,表示没有线程独占
    if (c == 0) {
    //设置为true
        free = true;
        //当前独占线程置空
        setExclusiveOwnerThread(null);
    }
    //cas设置state
    setState(c);
    return free;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值