3. Speaking from AbstractQueued Synchronizer (AQS), (2) Lock acquisition and release in shared mode

Keywords: Java

In the previous section, the implementation process of the exclusive mode in AbstractQueued Synchronizer (AQS) for synchronization state acquisition and release is analyzed. This section will analyze the synchronization state acquisition and release process of shared mode. The last section mentioned the difference between exclusive mode and shared mode. The main difference is whether multiple threads can get synchronization at the same time.

1. Acquisition of Synchronization State of Shared Mode

This method is the same as the acquisition method of acquiring synchronization state in exclusive mode. We briefly review the acquisition method of acquiring synchronization state in exclusive mode.

//AbstractQueuedSynchronizer#acquire
public final void acquire(int arg) {
    if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))    //Acquisition locks(tryAcquire)->Constructing Nodes(addWaiter)->Join the queue(addWaiter)->Spin acquisition lock(acquireQueued)
    selfInterrupt();    //Interrupt the current thread
}
//AbstractQueuedSynchronizer#acquireShared
public final void acquireShared(int arg) {
    if (tryAcquireShared(arg)) //Get locks, implemented by subclasses
    doAcquireShared(arg);
}
private void doAcquireShared(int arg) {
    final Node node = addWaiter(Node.SHARED);
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
            final Node p = node.predecessor();
            if (p == head) {
                int r = tryAcquireShared(arg);
            if (r >= 0) {
                setHeadAndPropagate(node, r);
                p.next = null;
                if (inerrupted) 
                    selfInterrupt();
                failed = false;
                return;
            }
        }
        if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())
        interrupted = true;
    }
} finally {
    if (failed)
        cancelAcquire(arg);    
    }
}

The spin process of acquiring synchronization state in shared mode is similar to that in exclusive mode. The difference from code implementation is that in shared mode, thread construction nodes are added to the queue, and after acquiring synchronization state, interrupting the current thread is placed in the same method, doAcquireShared. Sharing mode also attempts to get synchronization status only when its predecessor node is the header node. When tryAcquireShared is called to get synchronization status successfully, the number greater than or equal to 0 will be returned. At this time, the setHeadAndPropagate method will be executed. This method first places the thread currently obtaining synchronization status as the header node (the same as exclusive mode), but After setting the current thread as the header node, a part of the operation is done. The code is as follows:

private void setHeadAndPropagate(Node node, int propagate) {
    Node h = head;
    setHead(node);    //Set the current thread node acquired to synchronization state as the header node 
    if (propagate > 0 || h == null || h.waitStatus < 0) {    //Wake up successor node
    Node s = node.next;
    if (s == null || s.isShared()) 
        doReleaseShared();    //Wake up successor nodes, because they are in shared mode, allowing multiple threads to get synchronization status at the same time
    }
}

In the doReleaseShared method, all nodes in the queue are first facilitated. If the node state is SIGNAL, the SIGNAL state is set to 0 (initial state), and the subsequent node of the node is awakened by calling unparkSuccessor. If the node state is 0, the state is set to PROPAGATE.

2. Release of synchronization state in shared mode

The implementation of this method is similar to the exclusive mode, and it is also a template method. The specific release implementation is customized by subclasses, which will wake up the successor nodes after the synchronization state is successfully released:

public final boolean releaseShared(int arg) {
    if (tryReleaseShared(arg)) {    //Release synchronization state
        doReleaseShared();    //Wake up successor node
        return true;
    }
    return false;
}

The above is the acquisition and release of synchronization state by shared mode in AQS. After the analysis of exclusive mode, the analysis of shared mode becomes much easier. The next section will continue to explore some specific details in the AbstractQueuedSynchronizer class.

Posted by dwu on Sat, 29 Jun 2019 15:27:40 -0700