Java Concurrency - queue synchronizer (AbstractQueuedSynchronizer)

Queue synchronizer (the AQS)

AbstractQueuedSynchronizer queue synchronizer (hereinafter referred to as synchronizer), is used to build the base frame synchronization locks or other components, it uses a member variable int represents the synchronization state, access to resources to complete the work queue thread through the built-in FIFO queue.

The main use synchronizer is inherited, the subclass through inheritance synchronizer and implement its abstract methods to manage the synchronization status, will inevitably have to make changes to the synchronization status in the implementation process of the abstract method, then you need to use synchronizer provided method 3 (getState (), setState (int newState) and compareAndSetState (int expect, int update) ) to operate, because they ensure that the change of state is secure. Subclass recommendation is defined as a custom static inner classes synchronous assembly , synchronizer itself does not implement any synchronization interface, it is merely defines the method several synchronous state acquisition and release to supply custom synchronization component use, synchronization can both support exclusive access to synchronized state can also support shared access to the synchronized state, it allows easy assembly of different types of synchronization (ReentrantLock, ReentrantReadWriteLock CountDownLatch and the like).

The synchronizer is the key lock (synchronization component may be any), the polymerization to achieve synchronization in the lock, the lock is implemented using synchronous semantics. Can understand the relationship between the two: the lock is facing the user, which defines the user interface to interact with a lock (such as two threads may allow concurrent access), hides the implementation details; synchronizer is facing the lock implementor, which simplifies the implementation of the lock, the synchronization status management screen, the thread line, and waiting for wakeup underlying operating. Locking and synchronization is well isolated areas required for users and implementers of concern.

Example interface queue synchronizer

Synchronizer design is based on a template method pattern, that is, the user needs to inherit and override the synchronization method specified, then the synchronizer in combination to implement a custom synchronous assembly and method for synchronizing the template provided by calling and these methods will call the method template user rewritten.

When the method specified by the synchronization rewritten using the following three methods require synchronization to provide access or modify the synchronization state.

  • getState (): Gets the current sync status.
  • the setState (newState The int): Set the current synchronization state.
  • compareAndSetState (Expect int, int Update): CAS is used to set the current state, the state of the process to ensure
    atomicity provided.

Method synchronizer rewritable follows:

Here Insert Picture Description
Here Insert Picture Description
Implement custom synchronization component, the template provided by the synchronization method will be called, which (part) and the template described methods:
Template Method synchronizer:
Here Insert Picture Description
Template synchronization method provides substantially divided into three categories: exclusive acquires synchronization state is released , shared acquire and release synchronization state and waits for thread synchronization queue query . Custom Sync component will use the template provided by the synchronization method to achieve their synchronization semantics.

Example: Custom exclusive locks

As the name suggests, is the exclusive lock at the same time, only one thread to acquire the lock, while the other thread can acquire the lock
in sync queue waiting, only to acquire the lock thread to release the lock, subsequent threads will be able to acquire a lock

package pers.zhang.part5;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

/**
 * @author zhang
 * @date 2020/1/20 - 17:42
 *
 * 使用AQS自定义独占锁
 */
public class Mutex implements Lock {
    //静态内部类,自定义同步器
    private static class Sync extends AbstractQueuedSynchronizer{
        //是否处于占用状态
        @Override
        protected boolean isHeldExclusively() {
            return getState() == 1;
        }

        //当状态为0的时候获取锁
        @Override
        protected boolean tryAcquire(int arg) {
            if(compareAndSetState(0, 1)){
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        //释放锁,将状态设置为0
        @Override
        protected boolean tryRelease(int arg) {
            if(getState() == 0)
                throw new IllegalArgumentException();
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }
        
        //返回一个Condition,每个condition都包含一个condition队列
        Condition newCondition(){
            return new ConditionObject();
        }
    }
    
    //将操作代理到Sync上
    private final Sync sync = new Sync();
    
    @Override
    public void lock() {
        sync.acquire(1);
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

    @Override
    public boolean tryLock() {
        return sync.tryAcquire(1);
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(time));
    }

    @Override
    public void unlock() {
        sync.release(1);
    }

    @Override
    public Condition newCondition() {
        return sync.newCondition();
    }
    
    public boolean isLocked(){
        return sync.isHeldExclusively();
    }
    
    public boolean hasQueuedThreads(){
        return sync.hasQueuedThreads();
    }
}

In the above example, exclusive locks Mutex is a synchronization custom component that allows only one thread owns the lock at the same time. Mutex defines a static internal class, the class inherits the inner synchronizer and implements exclusive acquire and release synchronization status. tryAcquire (int acquires) method, if the setting is successful after CAS (synchronization state is set to 1), it means acquiring a synchronization state, but rather reset to zero in synchronization state tryRelease (int releases) method. And will not achieve internal synchronizer deal directly with the user to use Mutex, but call the method Mutex provided in achieving Mutex in order to obtain the lock lock () method, for example, only need to call in the synchronous method implementations the template method acquire (int args) to the current thread calls this method to get the synchronization state failure will be added to the queue waiting for synchronization, thus greatly reducing custom implementation of a reliable synchronization component threshold.

Published 627 original articles · won praise 1857 · Views 230,000 +

Guess you like

Origin blog.csdn.net/cold___play/article/details/104054572