【JUC源码学习01】AQS学习

本文详细介绍了AQS的成员变量、工作原理,特别是独占式和共享式同步状态的获取与释放。通过分析ReentrantLock的实现,探讨了AQS的acquire和release方法,以及在超时获取和线程唤醒过程中的关键函数。此外,还讨论了AQS在读写锁和线程池中的应用。
摘要由CSDN通过智能技术生成

AQS(AbstractQueuedSynchronizer) 学习

AbstractQueuedSynchronizer 本身是个抽象类。

在这个抽象类里,有两个内部类,一个是 Node,一个 ConditionObject 类。

还有其他的一些属性变量。

一、AQS 成员变量

		//Head of the wait queue, lazily initialized. Except for initialization, it is modified only via method setHead. Note: If head exists, its waitStatus is guaranteed not to be CANCELLED.
		private transient volatile Node head;

    /**
     * Tail of the wait queue, lazily initialized.  Modified only via
     * method enq to add new wait node.
     */
    private transient volatile Node tail;

    /**
     * The synchronization state.
     * 同步状态
     * 如果 state=0,则锁未被线程获取;若 state≠0,说明锁已经被获取。不同的类实现也不一样,比如读写锁的读锁,可以允许多个线程获取锁
     */
    private volatile int state;

		
    // 获取同步状态
    protected final int getState() {
   
        return state;
    }

    //设置同步状态
    protected final void setState(int newState) {
   
        state = newState;
    }

    // 使用CAS 设置当前状态,该方法能够保证状态设置的原子性
    protected final boolean compareAndSetState(int expect, int update) {
   
        // See below for intrinsics setup to support this
        return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
    }

自定义同步组件实现的两个步骤:

1、自定义类实现 Lock接口

2、自定义类内部创建静态内部类Sync,这个静态内部类继承 AQS,并重写其获取锁、释放锁的状态。

3、将自定义同步组件类的获取锁和释放锁的操作,代理到Sync 上。

二、AQS 同步器的工作原理

  • 独占锁:独占锁就是同一时刻只能有一个线程获取到锁,而其他获取锁的线程只能处于同步队列中等待,只有获得锁的线程释放了锁,后继的线程才能够释放锁。
  • 共享锁:

Node 节点

static final class Node {
   
        // 有共享模式和独占模式,默认是共享模式
        static final Node SHARED = new Node();
        static final Node EXCLUSIVE = null;

        // waitStatus的 4 种状态,描述的是当前队列中节点中的线程的四种状态
        static final int CANCELLED =  1;
        static final int SIGNAL    = -1;
        static final int CONDITION = -2;
        static final int PROPAGATE = -3;

        // 下一个线程的等待状态,为 0 则为唤醒状态
        volatile int waitStatus;

       // 当前节点的前驱节点
        volatile Node prev;

        // 当前节点的后驱节点
        volatile Node next;

        // 当前节点的线程
        volatile Thread thread;

        // 当前节点的下一个节点是哪种模式
        Node nextWaiter;

        /**
         * Returns true if node is waiting in shared mode.
         */
        final boolean isShared() {
   
            return nextWaiter == SHARED;
        }

       // 返回当前节点的前驱节点
        final Node predecessor() throws NullPointerException {
   
            Node p = prev;
            if (p == null)
                throw new NullPointerException();
            else
                return p;
        }

        Node() {
       // Used to establish initial head or SHARED marker
        }

        Node(Thread thread, Node mode) {
        // Used by addWaiter
            this.nextWaiter = mode;
            this.thread = thread;
        }

        Node(Thread thread, int waitStatus) {
    // Used by Condition
            this.waitStatus = waitStatus;
            this.thread = thread;
        }
    }

三、独占式同步状态获取与释放

以可重入锁 ReentrantLock 为例:

1、ReentrantLock#lock()方法

public void lock() {
   
    sync.lock();
}

下面以公平锁的实现进行学习:

2、ReentrantLock.FairSync#lock

 	final void lock() {
   
      acquire(1);
  }

下面进行调用分析:

3、AbstractQueuedSynchronizer#acquire(int arg)方法

java.util.concurrent.locks.AbstractQueuedSynchronizer#acquire

 	// 获取锁,调用tryAcquire获取锁,如果获取锁失败,即返回 false
  // 返回 false,则将当前线程的等待状态设置为EXCLUSIVE,同时将其加入到同步队列当中等待,当前线程自己中断
 	public final void acquire(int arg) {
   
     // 1、tryAcquire :同步状态的获取
     // 2、节点构造
     // 3、addWaiter:加入同步队列
     // 4、acquireQueued:在同步队列中自旋
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            // 自己中断
            selfInterrupt();
    }

上面的主要流程是:

  • 1、调用方法:tryAcquire,尝试获取锁
  • 2、如果获取锁失败,则调用方法:addWaiter,将当前线程加入到等待队列当中,同时设置当前线程的状态为:EXCLUSIVE
  • 3、执行acquireQueued方法,不断自旋获取锁,
  • 4、如果获取不到锁,则将当前线程中断。
3.1 tryAcquire(int acquires) 方法

java.util.concurrent.locks.ReentrantLock.FairSync#tryAcquire

下面一一来看下里面的方法:

tryAcquire(int acquires)方法是获取锁,如果获取锁失败则返回 flase。该方法有公平锁和非公平锁两种实现

			// 公平锁获取
			protected final boolean tryAcquire(int acquires) {
   
            // 获取当前线程
            final Thread current = Thread.currentThread();
            // 先获取同步状态
            int c = getState(); 
            // 如果当前同步状态为 0,说明锁还没有被获取
            if (c == 0) {
   
                // 若同步状态符合预期,则进行 CAS 设置同步状态(初次设置同步状态是CAS 进行设置)
                 // 观察下面的非公平锁的实现,发现两者获取锁时,代码多了一个hasQueuedPredecessors()方法
                 // 这个方法用于判断当前线程之前是否有等待线程,如果没有的话,就会执行 cas 操作进行加锁
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
   
                    // 将当前线程设置给exclusiveOwnerThread线程,表示同步状态已被当前线程独占式获取
                    setExclusiveOwnerThread(current);
                    // 表示已独占式获取到锁
                    return true;
                }
        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值