Java多线程之AQS源码分析

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,写锁获取`

锁降级

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

发布了8 篇原创文章 · 获赞 1 · 访问量 169

猜你喜欢

转载自blog.csdn.net/qq_41725735/article/details/105268037