【juc】AQS principle

I. Overview

  • 1. It is an abstract parent class, the full name is AbstractQueuedSynchronizer, which is the framework of blocking locks and related synchronizer tools
  • 2. The usage is that the synchronizer class inherits the parent class to implement the methods of the parent class, and calls the methods of the synchronizer class to achieve the purpose of locking and unlocking, etc.

2. Features

  • 1. Use the state attribute to represent the state of the resource (divided into exclusive mode and shared mode). Subclasses need to define how to maintain this state and control how to acquire and release locks
  • 2. getState is used to get the state state
  • 3.setState is used to set the state state
  • 4. compareAndSetState uses the cas optimistic lock mechanism to set the state state
  • 5. Exclusive mode is that only one thread can access resources, while shared mode allows multiple threads to access resources
  • 6. Provides a waiting queue based on FIFO (first in, first out), similar to Monitor's EntryList
  • 7. Use condition variables to implement the waiting and wake-up mechanism, support multiple condition variables, similar to Monitor's WaitSet
  • 8. The main methods implemented by subclasses are tryAcquire, tryRelease, tryAcquireShared, tryReleaseShared, isHeldExclusively, and UnsupportedOperationException will be thrown by default
  • 9. Acquire the lock
// 如果获取锁失败
if(!tryAcquire(arg){
	// 入队列,可以选择阻塞当前线程,用的是park和unpark机制
}
  • 10. Release the lock
// 如果释放锁成功
if(tryRelease(arg)){
	// 让阻塞线程恢复运行
}

3. Realize non-reentrant lock

package com.learning.aqs;

import lombok.extern.slf4j.Slf4j;

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

/**
 * 自定义不可重入锁
 */
@Slf4j
public class NotReentrantLock implements Lock {
    /**
     * 同步器类
     * 独占锁实现
     */
    class Sync extends AbstractQueuedSynchronizer{
        /**
         * 尝试获取锁
         * @param arg 用于可重入锁的计数操作
         * @return
         */
        @Override
        protected boolean tryAcquire(int arg) {
            // 避免其它线程也调用该方法,只能有一个线程加锁成功
            if(compareAndSetState(0, 1)){
                // 加上锁,并设置owner为当前线程
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        /**
         * 尝试释放锁
         * @param arg
         * @return
         */
        @Override
        protected boolean tryRelease(int arg) {
            // 将owner线程置为空,state状态设置为0,即为解锁
            setExclusiveOwnerThread(null);
            // volatile int state; state是volatile修饰的,改值后会加入写屏障,写屏障之前的改动都会同步到主内存中,因此setExclusiveOwnerThread要放在上面
            setState(0);
            return true;
        }

        /**
         * 是否持有独占锁
         * @return
         */
        @Override
        protected boolean isHeldExclusively() {
            return getState() == 1;
        }

        public Condition newCondition(){
            return new ConditionObject();
        }
    }

    private Sync sync = new Sync();

    /**
     * 加锁(不成功则进入等待队列中等待)
     */
    @Override
    public void lock() {
        // 当前线程尝试加锁,如果尝试加锁不成功,将当前线程放入等待队列,tryAcquire只会尝试一次
        sync.acquire(1);
    }

    /**
     * 可打断加锁
     * @throws InterruptedException
     */
    @Override
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

    /**
     * 尝试加锁,尝试1次
     * @return
     */
    @Override
    public boolean tryLock() {
        return sync.tryAcquire(1);
    }

    /**
     * 尝试加锁,带超时时间
     * @param time
     * @param unit
     * @return
     * @throws InterruptedException
     */
    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(time));
    }

    /**
     * 解锁
     */
    @Override
    public void unlock() {
        // tryRelease会将状态置为0,将owner线程置为null,不会唤醒等待队列中的阻塞线程
        // release会调用tryRelease方法,改状态为0,将owner线程置为null,唤醒等待队列中的头个线程
        sync.release(1);
    }

    /**
     * 创建条件变量
     * @return
     */
    @Override
    public Condition newCondition() {
        return sync.newCondition();
    }


    public static void main(String[] args) {
        NotReentrantLock lock = new NotReentrantLock();
        new Thread(()->{
            lock.lock();
            try{
                log.debug("locking...");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                log.debug("unlocking...");
                lock.unlock();
            }
        }, "t1").start();
        new Thread(()->{
            lock.lock();
            try{
                log.debug("locking...");
            }finally {
                log.debug("unlocking...");
                lock.unlock();
            }
        }, "t2").start();
    }
}

Guess you like

Origin blog.csdn.net/qq_32088869/article/details/131902234