【Java多线程】浅谈AQS

浅谈AQS(AbstractQueuedSynchronizer)

一、简介

	AQS全称AbstractQueuedSynchronizer,在java中多线程工具包JUC是基于AQS实现的
	技术核心:共享(volatile)state + 双向链表
	实现方法:CAS操作
	设计模式:模板模式(Template Pattern):父类画模,子类重写

二、源码分析

	下面通过ReentrantLock源码进行分析:
  1. sync调用了lock方法,以下lock()方法具体实现:
final void lock() {
            if (compareAndSetState(0, 1))  //第一个线程进来通过CAS操作更新为1
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);	//否则调用acquire()方法
        }
        
  1. 跟进到acquire()方法中:
public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
	可以看出又调用了自身的tryAcquire(arg)方法(拿到锁),跟进到里面发现又调用了nonfairTryAcquire(int acquires)
final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState(); //AQS核心数值 state出场
            //state为0无人上锁
            if (c == 0) {
            	//CAS操作将0改为1,给线程上锁
                if (compareAndSetState(0, acquires)) {
                	//设置当前线程唯一拥有这把锁
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            //判断当前线程是否拥有这把锁
            else if (current == getExclusiveOwnerThread()) {
            	//重入
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

假如新进线程没有拿到锁调用acquireQueued(addWaiter(Node.EXCLUSIVE), arg)方法,先看addWaiter()方法:

 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)) {//CAS操作设置新节点为tail末端
                pred.next = node;
                return node;
            }
        }
        enq(node);
        return node;
    }

acquireQueued()方法:

final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
                //判断前置节点是否是头节点并且尝试拿一下锁,这就解释了为什么是双向链表的原因
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                //队列中等着被唤醒
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }
  • 配一张图 配合理解
    在这里插入图片描述

三、总结

	AQS(AbstractQueuedSynchronizer)的核心就是CAS操作双向链表(head and tail)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值