1. What is AQS

AQS is short for AbstractQueuedSynchronizer, is used to construct the lock or other synchronous component based framework, it USES the int member variable synchronous state, through the built-in FIFO (First in First out) queue to complete resources for thread line work.

2. What is the relationship between AQS and locks?

AQS is the key to the implementation of lock, in the implementation of lock synchronizer aggregation, using synchronizer to realize the semantics of lock. The relationship between the two can be understood as follows:

  1. The lock is consumer-oriented, and it defines the interface that the consumer interacts with the lock, hiding the implementation details
  2. Synchronizer is a lock-oriented implementor, which simplifies the implementation and hides the low-level operations such as synchronization state management, thread queuing, waiting and waking up
  3. The lock and synchronizer provide a good separation between the user and the area of attention that the idle person needs

3. How to use it?

Define the synchronization component, and implement the AQS synchronizer internally through the static inner class Sync. The code is as follows:

package com.alwyn.nettysample.synchronizer;

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

public class Mutex implements Lock {

    private final Sync sync = new Sync();

    private static class Sync extends AbstractQueuedSynchronizer {

        @Override
        protected boolean isHeldExclusively() {
            return getState() == 1;
        }

        @Override
        public boolean tryAcquire(int arg) {
            if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        @Override
        protected boolean tryRelease(int releases) {
            if (getState() == 0) {
                throw new IllegalMonitorStateException();
            }
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }

        Condition newCondition() {returnnew ConditionObject(); } } @Override public voidlock() {
        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();
    }

    public Collection<Thread> getQueuedThreads() {
        returnsync.getQueuedThreads(); }}Copy the code

Build the project quickly by SpringBoot, where the controller code is as follows:

package com.alwyn.nettysample.controller;

import com.alwyn.nettysample.synchronizer.Mutex;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Collection;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

@RestController
public class HelloController {
    private int count = 0;
    private AtomicInteger integer = new AtomicInteger(0);
    Mutex lock = new Mutex();

    @RequestMapping("/hi")
    public String hi() {
        try {
            int i = integer.incrementAndGet();
            System.out.println("request count:" + i);
            boolean flag = lock.tryLock(100, TimeUnit.MILLISECONDS);
            if (flag) {
                count++;
                System.out.println("count = " + count);
                Thread.sleep(10);
                lock.unlock();
            } else {
                boolean b = lock.hasQueuedThreads();
                Collection<Thread> queuedThreads = lock.getQueuedThreads();
                for (Thread thread : queuedThreads) {
                    System.out.println(thread.getId() + "... "" + thread.getName() + "... "" + thread.getState() + "... "" + thread.getThreadGroup());
                }
                System.out.println("Failed to acquire lock :" + b);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


        return "say hi world";
    }

    @RequestMapping("/reset")
    public void setValue() { integer.set(0); count = 0; }}Copy the code

Set concurrent request locks through Jmeter

Results: