Java多线程之AQS源码分析

本文深入剖析Java的AQS(AbstractQueueSynchronizer),讲解其如何利用volatile state保证线程可见性,以及lock()、unlock()的独占式操作,读写锁的工作原理和锁降级的机制。详细解读了acquire()、addWaiter()、acquireQueued()等关键方法和waitStatus的状态管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

AQS源码分析

AQS(AbstractQueueedSynchronizer)使用一个int成员变量表示同步状态,通过内置的FIFO队列完成资源获取的排队工作
图片来自马士兵教育多线程
voaltile state 是为了保证state变量线程的可见性,
AQS改变state的方法主要有以下3个

getState()
setState()
compareAndSetState()

采用CAS添加节点到队列中好处
不必锁住整个链表就可以实现添加节点

lock()方法独占式

首先调用sync的acquire方法

    public void lock() {
        sync.acquire(1);
    }

进入AQS,调用acqurie()方法

    public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

第一个分支执行tryAcquire(),

        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }

点进去之后发现执行的nonfairTryAcquire()

/**
*尝试获取锁,成功返回true,失败返回false
**/
final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            //获取当前的标志的状态
            int c = getState();
            //c==0表示没人获取这把锁
            if (c == 0) {
            	//使用CAS操作尝试获取这把锁
                if (compareAndSetState(0, acquires)) {
                	//如果获取成功,设置为独占线程
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            //如果该线程已经占有了该锁,将标志位加1,这就是可重入的原理
            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;
        }

如果tryAccquire()返回false,进入acquireQueued(addWaiter(Node.EXCLUSIVE), arg)分支
首先,来看下addWaiter()的源码

private Node addWaiter(Node mode) {
		//创建一个新的节点
        Node node = new Node(mode);
		//for是个死循环,不达目的不罢休
        for (;;) {
        	//tail是等待队列的尾巴节点
            Node oldTail = tail;
            if (oldTail != null) {
            	//尾部节点不为空,用setPrevRelaxed()函数设置
            	//node的上一节点
                node.setPrevRelaxed(oldTail);
                //通过CAS操作加入等待队列
                if (compareAndSetTail(oldTail, node)) {
                    oldTail.next = node;
                    return node;
                }
            } else {
                initializeSyncQueue();
            }
        }
    }
    //初始化等待队列
private final void initializeSyncQueue() {
        Node h;
        if (HEAD.compareAndSet(this, null, (h = new Node())))
            tail = h;
    }

下面查看acquireQueued方法

final boolean acquireQueued(final Node node, int arg) {
        boolean interrupted = false;
        try {
        	//死循环
            for (;;) {
            	//p为node的前驱
                final Node p = node.predecessor();
                //如果p为头节点,tryAcquire成功
                if (p == head && tryAcquire(arg)) {
                	//设置node为头节点,也就是获取锁
                    setHead(node);
                    p.next = null; // help GC
                    return interrupted;
                }
                if (shouldParkAfterFailedAcquire(p, node))
                    interrupted |= parkAndCheckInterrupt();
            }
        } catch (Throwable t) {
            cancelAcquire(node);
            if (interrupted)
                selfInterrupt();
            throw t;
        }
    }

    /**
     * 如果尝试获取锁失败,检查并更新节点状态.
     * 如果节点线程被block住就返回true
     *
     *
     * @param pred node's predecessor holding status
     * @param node the node
     * @return {@code true} if thread should block
     */
    private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        int ws = pred.waitStatus;
        if (ws == Node.SIGNAL)
            /*
             * This node has already set status asking a release
             * to signal it, so it can safely park.
             * 
             */
            return true;
        if (ws > 0) {
            /*
             * Predecessor was cancelled. Skip over predecessors and
             * indicate retry.
             * 大于0跳过节点
             */
            do {
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
            pred.next = node;
        } else {
            /*
             * waitStatus must be 0 or PROPAGATE.  Indicate that we
             * need a signal, but don't park yet.  Caller will need to
             * retry to make sure it cannot acquire before parking.
             */
            pred.compareAndSetWaitStatus(ws, Node.SIGNAL);
        }
        return false;
    }


waitStatus主要有以下几种状态

        static final Node EXCLUSIVE = null;

        /** waitStatus value to indicate thread has cancelled. */
        static final int CANCELLED =  1;
        /** waitStatus value to indicate successor's thread needs unparking. 后继unpark*/
        static final int SIGNAL    = -1;
        /** waitStatus value to indicate thread is waiting on condition. condition队列*/
        static final int CONDITION = -2;
        /**
         * waitStatus value to indicate the next acquireShared should
         * unconditionally propagate.
         */
        static final int PROPAGATE = -3;

Signal
The successor of this node is (or will soon be) blocked (via park), so the current node must unpark its successor when it releases orcancels. To avoid races, acquire methods mustfirst indicate they need a signal, then retry the atomic acquire, and then,on failure, block.
当前节点必须unpark()后继节点当当前节点释放资源或取消掉的时候

unLock()独占式

进入release

    public void unlock() {
        sync.release(1);
    }
    public final boolean release(int arg) {
    	//释放资源成功
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
            //唤醒后继
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

tryRelease()

//当c=0,释放资源
protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

读写锁

main(){
ReentrantReadWriteLock reentrantLock = new ReentrantReadWriteLock();
        reentrantLock.readLock().lock();
}

调用sync.acqurireShared()

        public void lock() {
            sync.acquireShared(1);
        }

调用模板方法

   public final void acquireShared(int arg) {
        if (tryAcquireShared(arg) < 0)
            doAcquireShared(arg);
    }

tryAcquireShared(int arg)方法返回值为int类型,当返回值大于等于0时,表示能够获取到同步状态
doAcquireShared ()加入等待队列

在这里插入图片描述
标志位为32位
读状态高16位,写状态低16位
写状态=state&0x0000FFFF
读状态=state>>>16
写状态加1=state+1
读状态加1=state+(1<<<16)
当state>0,state&0x0000FFFF=0,state>>>16 > 0,读锁获取
state>0state&0x0000FFFF>0,state>>>16 >=0,写锁获取`

锁降级

锁降级指的是写锁降级成为读锁。如果当前线程拥有写锁,然后将其释放,最后再获取读锁,这种分段完成的过程不能称之为锁降级。锁降级是指把持住(当前拥有的)写锁,再获取到读锁,随后释放(先前拥有的)写锁的过程

### 关于 AQS (AbstractQueuedSynchronizer) 源码分析 #### AQS 基本概念 AQS 是 `java.util.concurrent` 包下用于构建锁和其他同步组件的基础框架[^1]。作为一个抽象类,AQS 提供了一种机制来管理线程之间的排队和阻塞/唤醒操作。 #### 核心成员变量 - **exclusiveOwnerThread**: 继承自父类 `AbstractOwnableSynchronizer`,表示当前持有独占锁的线程对象[^3]。 此字段有助于追踪哪个线程正在占用资源,在调试或监控时非常有用。 #### 同步队列结构 AQS 使用 FIFO 队列来维护等待获取锁或其他同步状态的线程列表。当一个线程尝试获取某个资源失败时会被加入到这个队列中,并进入休眠直到被其他线程唤醒。 #### 主要方法解析 为了支持不同的同步需求,AQS 定义了一系列模板方法让子类去实现: - `tryAcquire(int arg)` 和 `tryRelease(int arg)` 这两个方法由具体的同步器实现,用来控制如何获取和释放共享资源的状态变化逻辑[^5]。 - `isHeldExclusively()` 判断当前线程是否已经持有了独占式的锁。 此外还有多个辅助性的内部方法如 `acquireQueued(Node node, int arg)` 来处理实际的入队、出队以及线程调度工作。 #### LockSupport 工具类的作用 在 AQS 实现过程中大量使用到了 `LockSupport.park()` 及其变体函数来进行线程挂起与恢复的操作[^4]。这些 API 能够高效地使线程暂停执行并响应中断信号,从而实现了轻量级且高性能的线程间通信方式。 ```java // 示例代码展示 park 方法调用场景 public final void acquireInterruptibly(int arg) throws InterruptedException { if (!tryAcquire(arg)) doAcquireInterruptibly(arg); } private void doAcquireInterruptibly(int arg) throws InterruptedException { final Node node = addWaiter(Node.EXCLUSIVE); boolean failed = true; try { for (;;) { final Node p = node.predecessor(); if (p == head && tryAcquire(arg)) { setHead(node); p.next = null; // help GC failed = false; return; } if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) throw new InterruptedException(); } } finally { if (failed) cancelAcquire(node); } } ``` 通过上述介绍可以看出,AQS 不仅是一个强大的底层设施,而且设计精巧合理,能够很好地满足各种复杂并发环境下的需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值