[java concurrent programming] AQS framework

1. Introduction

 The full name of aqs is the abstract queue synchronizer, which is the AbstractQueuedSynchronize abstract class.
It is a framework for building locks and synchronizers. It uses CAS technology at the bottom to ensure the atomicity of operations. At the same time, it uses FIFO queues to achieve lock competition between threads. It puts basic synchronization-related abstract details in AQS, which can It becomes the basis for realizing most of the synchronization requirements, and is also the core basic component of JUC's concurrent package synchronization. Lock, ReadWriteLock, CountDowndLatch, CyclicBarrier, Semaphore, ThreadPoolExecutoretc. are all realized on the basis of AQS.

2. The core idea of ​​AQS

If the requested shared resource is idle, the thread currently requesting the resource is set as an effective worker thread, and the shared resource is set to a locked state. If the requested shared resource is occupied, a mechanism for thread blocking and waiting and lock allocation when awakened is required. This mechanism AQS is implemented with CLH queue lock, and the thread that cannot acquire the lock temporarily is added to the queue.

AQS uses a volatile state variable to represent the synchronization state, and completes the queuing work of obtaining resource threads through the built-in FIFO queue. AQS uses CAS to perform atomic operations on the synchronization state to modify its value.

1. The specific locking process

1. Execute the tryAcquire method to try to lock

2. If it is judged that the current thread is itself, then add state+1 and the lock is successful. If it is not to continue to judge whether the current lock is free (whether the state is 0), if it is, lock it through cas and return the locking result (implemented by subclasses)

3. If locking fails, encapsulate the current thread into a Node object, point Node.prev to tail to form a linked list structure, and execute LockSupport.park(this) if the thread needs to be blocked;

 

2. The specific lock release process

1. Execute the tryRelease method to release the lock

2. State performs -1 operation, if it is 0, set the current thread ExclusiveOwnerThread to null. Otherwise set State-1 value

3. If there is a waiting thread, use LockSupport.unpark to wake up the thread that wraps the next node of Node

3. aqs icon

Mainly contains 4 fields

  • state (synchronous state)
  • exclusiveOwnerThread (the thread that acquires the lock)
  • head (head node)
  • tail tail node

aqs is divided into two kinds of "exclusive lock" and "shared lock"

  • Exclusive lock - the lock can only be occupied by one thread lock at a time. For example: ReentrantLock reentrant lock and ReentrantReadWriteLock.WriteLock write lock.

        Exclusive locks are further divided into "fair locks" and "unfair locks".

  1. Fair lock is to acquire locks fairly according to the first-come, first-served rule;
  2. Unfair lock, when the thread wants to acquire the lock, it directly preempts and acquires the lock
  • Shared lock - a lock that can be owned by multiple threads at the same time and can be shared. For example: ReentrantReadWriteLock.ReadLock read lock, CyclicBarrier cycle barrier, CountDownLatch counter and Semaphore semaphore

3. AQS implements subclasses

1. CountDownLatch counter (commonly used)

In CountDownLatch, count down means the countdown, and latch means the latch. The overall meaning can be understood as a countdown door bolt, which seems to have a feeling of "three two one, all threads run together after the door is opened".
 

Instructions

First create a CountDownLatch object, and the incoming parameter is the initial value of count. If a thread calls the await() method, then the thread enters the blocked state and enters the blocking queue. If a thread calls the countDown() method, it will make count-1; when the value of count is 0, the threads calling the await() method in the blocking queue will be awakened one by one to enter the subsequent operation.

Common methods are:

  1. The await() method means blocking the thread
  2. The countDown() method indicates that the counter is decremented by one. After the thread is blocked, all blocked threads can be woken up after the counter is reduced to 0.

scenes to be used

  1. Let multiple threads wait: Simulate concurrency and let concurrent threads execute together
  2. Let a single thread wait: After multiple threads (tasks) are completed, aggregate and merge

2. Semaphore semaphore

Semaphore(信号量)The effect of current limiting can be achieved by limiting the number of threads executed (the number of threads accessing shared resources at the same time).

Instructions

When a thread executes, it first obtains a license through its method. The thread that has obtained the license continues to execute the business logic. When the thread execution is completed, the license is released. The thread that has not obtained the license waits or ends directly.

Common methods are:

  1. void acquire() throws InterruptedException Acquiring a license will block waiting for other threads to release the license
  2. void acquire(int permits) throws InterruptedException Acquiring the specified number of permits will block and wait for other threads to release
  3. void acquireUninterruptibly() Acquiring a license will block waiting for other threads to release the license and can be interrupted
  4. void acquireUninterruptibly(int permits) Acquiring the specified number of permits will block and wait for other threads to release permits, which can be interrupted
  5. boolean tryAcquire() tries to acquire permission without blocking waiting
  6. boolean tryAcquire(int permits) Try to acquire the specified number of permits without blocking waiting
  7. boolean tryAcquire(long timeout, TimeUnit unit) Try to get permission to specify the waiting time
  8. boolean tryAcquire(int permits, long timeout, TimeUnit unit) Try to acquire the specified number of permits to specify the waiting time

scenes to be used

  1. Control the maximum number of concurrent threads (current limiting, such as database connection pool)
  2. asynchronous task, return synchronously
  3. Locking (one shaping semaphore can simulate a mutex)

3. CyclicBarrier

CyclicBarrier literally means "reusable fence". Compared with CountDownLatch, CyclicBarrier is much simpler. It is a combination of ReentrantLock and Condition, but CyclicBarrier can have more than one barrier, because its barrier (Barrier) can be reused (Cyclic).

Using the CyclicBarrier class, a group of threads can wait for each other, and perform subsequent operations when all threads reach a certain barrier point.

Instructions

  

Common methods are:

  • public CyclicBarrier(int parties);//parties indicates the number of threads intercepted by the barrier
  • public CyclicBarrier(int parties, Runnable barrierAction);//parties indicates the number of threads intercepted by the barrier, when the thread reaches the barrier, the barrierAction is executed first
  • await()
  • isBroken() is used to know whether the blocked thread is interrupted
  • reset()
  • getNumberWaiting() gets the number of threads blocked by CyclicBarrier

scenes to be used

  1. It is used for multi-threaded calculation data and the application scenario of merging the calculation results at the end

The difference from CountDownLatch is that
CountDownLatch is a synchronous auxiliary class that allows one or more threads to wait for a group of other threads to complete operations before continuing.
CyclicBarrier is a synchronous auxiliary class that allows a group of threads to wait for each other to reach a common point before continuing.
the difference:

  1. The counter of CountDownLatch can only be used once. The counter of CyclicBarrier can be reset using the reset() method. So CyclicBarrier can handle more complex business scenarios, such as if a calculation error occurs, you can reset the counter and let the threads execute it again
  2. CyclicBarrier also provides getNumberWaiting(), isBroken() and other methods.
  3. CountDownLatch will block the main thread, and CyclicBarrier will not block the main thread, but only block the sub-threads.

4. Phaser stage

Phaser allows concurrent multi-phase tasks. The Phaser class mechanism is to synchronize the threads at the end of each step. When all threads have completed this step, they are allowed to execute the next step.

scenes to be used

It is used to solve the scenario problem of controlling multiple threads to complete tasks in stages.

5. Exchanger

Exchanger is used for communication and data exchange between threads. Exchanger provides a synchronization point exchange method. When two threads call the exchange method, regardless of the calling time, the two threads will wait for each other until the thread reaches the exchange method call point. At this time, the two threads can exchange data and output data from this thread passed to the other party.

6. ReentrantLock reentrant lock, ReentrantReadWriteLock reentrant read-write lock

Reference: [java concurrent programming] lock interface_Realistic, too cruel blog-CSDN blog

7. ThreadPool Executor thread pool

Reference: Java uses jdk's ThreadPoolExecutor thread pool_Reality, Too Cruel Blog-CSDN Blog

Guess you like

Origin blog.csdn.net/sumengnan/article/details/125058951