[architect interview - JUC concurrent programming - 8] - AQS

1: Why AQS

Locks and collaboration classes (semaphores) have something in common: they are similar to a gate (only some threads are allowed to pass through), because they all use a common base class AQS at the bottom

Because many of the above collaboration classes work similarly, you can extract a tool class and use it directly. For ReentrantLock and Semaphore, you can shield many details and only focus on their own business logic.

AQS is a tool class (framework) for building locks, synchronizers and collaboration tool classes. With AQS, more collaboration tool classes can be written easily.

2: Relationship between Semaphore and AQS

  Semaphore has a Sync class inside, which inherits AQS

     Similar to group face and single face in interview

AQS does HR work such as arranging seating, calling, first come, first served, etc. interviewers (concurrent) don't care whether the numbers of two interviewers will conflict, and they don't care if the interviewers need a place to sit and wait. These are all left to HR(AQS)

Semaphore: after a person's interview, the latter person can come in to continue the interview (license)

CountDownLatch: group face, need to wait for 10 people to come together for an interview.

For synchronization tools such as Semaphore and CountDownLatch, all you need to do is write down your rules for "important people", such as "one out, one in" or "gather 10 people for an interview".

The rest of the job of greeting the interviewer is done by AQS.

3: AQS principle

1: state: it will vary according to the specific implementation classes

For example, in Semaphore, it means "number of licenses remaining"

In countdown latch, it means "the number that needs to be counted down".

In ReentrantLock, state indicates the occupancy of the lock, including the reentrant count.

State is a volatile modifier and will be modified concurrently. Therefore, all methods to modify state need to ensure thread safety, such as getState, setState and compareAndSetState operations to read and update the state. These methods depend on the support of juc.atomic package.

2: FIFO queue for controlling thread lock grabbing and cooperation

This queue is used to store "waiting threads". AQS is the "queue manager". When multiple threads compete for the same lock, there must be a queuing mechanism to string together those threads that failed to get the lock. When the lock is released, the lock manager will select a suitable thread to occupy the newly released lock.

AQS will maintain a waiting thread queue and put all threads into the two-way linked list queue.

 

The head is the thread that gets the lock, followed by the thread waiting to get the lock.

3: The acquisition / release method expected to be implemented by the collaboration tool class

Here, the acquisition and release method is the most important method in the AQS collaboration tool class, which is implemented by the collaboration class itself, and has different meanings.

The acquisition operation depends on the state variable and is often blocked (when the lock cannot be obtained). For example, in Semaphore, the acquisition is the acquire method, which is used to obtain a license. If the state variable is > 0, it can be obtained, and the value will be reduced by 1

The release operation will not be blocked. For example, in Semaphore, release is the release method, which releases a license and increases the state variable by 1

4: AQS usage

Step 1: write a class, think about the cooperation logic, and implement the acquisition and release methods

Step 2: write a Sync class internally to inherit AbstractQueuedSynchronized

The third step is to invoke AQS's acquire/release or Shared methods in the previously acquired access / release method according to the exclusive or shared methods to rewrite tryAcquire/tryRelease or tryAcquireShared(int acquires) and tryReleaseShared(int release).

5: Use AQS to realize their own door latch

aqs/OneShotLatch.java

package aqs;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
/**
 * Description: I use AQS to implement a simple thread collaborator
 */
public class OneShotLatch {
    private final Sync sync = new Sync();
 
    //Obtain the lock using the information provided by AQS
    public void await() {
        sync.acquireShared(0);
    }
    //Release lock
    public void signal() {
        sync.releaseShared(0);
    }
 
    private class Sync extends AbstractQueuedSynchronizer {
        @Override
        protected int tryAcquireShared(int arg) {
            //state=1 release
            return (getState() == 1) ? 1 : -1;
        }
 
        @Override
        protected boolean tryReleaseShared(int arg) {
           setState(1);
           //Wake up all other waiting threads
           return true;
        }
    }
 
    public static void main(String[] args) throws InterruptedException {
        OneShotLatch oneShotLatch = new OneShotLatch();
        for (int i = 0; i < 10; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
     System.out.println(Thread.currentThread().getName()+"Try to get latch,If the acquisition fails, wait");
                    oneShotLatch.await();
                 System.out.println("Gate opening and release"+Thread.currentThread().getName()+"Continue running");
                }
            }).start();
        }
        //Release after 5 seconds
        Thread.sleep(5000);
        //Wake up the waiting thread.
        oneShotLatch.signal();
    }
}

Keywords: Java Interview architecture

Added by The Silent on Thu, 04 Nov 2021 15:53:30 +0200