Java multi-threaded AQS source code analysis

AQS source code analysis

AQS (AbstractQueueedSynchronizer) uses an int member variable to represent the synchronization state. The queuing work to complete resource acquisition through the built-in FIFO queue
The picture comes from the horse soldier education multithreading
is to ensure the visibility of the state variable thread.
AQS changes the state mainly in the following three ways

getState()
setState()
compareAndSetState()

The advantage of using CAS to add nodes to the queue is to add nodes
without locking the entire linked list

lock () method exclusive

First call sync's acquire method

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

Enter AQS and call acqurie () method

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

The first branch executes tryAcquire () ,

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

After clicking inside, I found 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;
        }

If tryAccquire () returns false, enter the acquireQueued (addWaiter (Node.EXCLUSIVE), arg) branch.
First, look at the source code of 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;
    }

View the acquireQueued method below

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 mainly has the following status

        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 must first indicate they need a signal, then retry the atomic acquire , and then, on failure, block. The
current node must be unpark () successor node when the current node releases resources or cancels it

unLock () exclusive

Enter 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;
        }

Read-write lock

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

Call sync.acqurireShared ()

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

Call template method

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

The return value of tryAcquireShared (int arg) method is of type int. When the return value is greater than or equal to 0, it indicates that the synchronization status can be obtained
doAcquireShared () join the waiting queue

Insert picture description here
The flag bit is 32 bits. The
read state is high 16 bits, and the write state is low 16 bits.
Write state = state&0x0000FFFF
read state = state>>>16
write state plus 1 = state + 1
read state plus 1 = state+(1<<<16)
when state> 0 state&0x0000FFFF=0,state>>>16 > 0, read lock acquires
state> 0 state&0x0000FFFF>0,state>>>16 >=0, write lock Get`

Lock downgrade

Lock downgrade refers to the downgrade of a write lock into a read lock. If the current thread owns the write lock, then releases it, and finally acquires the read lock, this process of segmentation completion cannot be called lock demotion. Lock downgrade refers to the process of holding the (currently owned) write lock, then acquiring the read lock, and then releasing the (previously owned) write lock

Published 8 original articles · Like1 · Visits 169

Guess you like

Origin blog.csdn.net/qq_41725735/article/details/105268037