10.AbstractQueuedSynchronizer(AQS)

AbstractQueuedSynchronizer(AQS)

AQS入门理论知识

概念

​ 抽象队列同步器,是用来实现锁或者其它同步器组件的公共基础部分的抽象实现,是重量级基础框架及整个JUC体系的基石,主要用于解决锁分配给"谁"的问题

​ 整体就是一个抽象的FIFO队列来完成资源获取线程的排队工作,并通过一个int类变量表示持有锁的状态

1689043965654

​ 双向队列:

*      +------+  prev +-----+       +-----+
* head |      | <---- |     | <---- |     |  tail
*      +------+       +-----+       +-----+

官网解释:

Provides a framework for implementing blocking locks and related synchronizers (semaphores, events, etc) that rely on first-in-first-out (FIFO) wait queues.

​ 为实现阻塞锁和相关的同步器提供一个框架,依赖于一个先进先出的等待队列

Subclasses can maintain other state fields, but only the atomically updated {@code int} value manipulated using methods {@link #getState}, {@link #setState} and {@link #compareAndSetState} is tracked with respect to synchronization.

​ 依靠单个原子int值来表示状态,通过占用和释放的方法,改变状态值

为什么AQS是JUC内容中最重要的基石

1689044159949

ReentrantLock中的AQS

public class ReentrantLock implements Lock, java.io.Serializable {
    private static final long serialVersionUID = 7373984872572414699L;
    /** Synchronizer providing all implementation mechanics */
    private final Sync sync;
    abstract static class Sync extends AbstractQueuedSynchronizer {}
}

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

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

锁和同步器的关系

​ 锁,面向锁的使用者定义了程序员和锁交互的使用层API,隐藏了实现细节,你调用即可。
​ 同步器,面向锁的实现者, Java并发大神DougLee,提出统一规范并简化了锁的实现,将其抽象出来屏蔽了同步状态管理、同步队列的管理和维护、阻塞线程排队和通知、唤醒机制等,是一切锁和同步组件实现的公共基础部分。

作用

加锁会导致阻塞有限塞就需要排队,实现排队必然需要队列

​ 抢到资源的线程直拨使用处理业务,抢不到资源的必然涉及一种排队等候机制。抢占资源失败的线程继续去等待(类似银行业务办理窗口都满了,暂时没有受理窗口的顾客只能去候客区排队等候),但等候线程仍然保留获取锁的可能且获取锁流程仍在继续(候客区的顾客也在等着叫号,轮到了再去受理窗口办理业务)。
​ 既然说到了排队等候机制,那么就一定会有某种队列形成,这样的队列是什么数据结构呢?
​ 如果共享资源被占用,就需要一定的阻塞等待唤醒机制来保证锁分配。这个机制主要用的是CLH队列的变体实现的将暂时获取不到锁的线程加入到队列中,这个队列就是AQS同步队列的抽象表现。它将要请求共享资源的线程及自身的等待状态封装成队列的结点对象(Node),通过CAS、自旋以及LockSupport.park()的方式,维护state变量的状态,使并发达到同步的效果。

AbstractQueuedSynchronizer源码:

​ AQS使用一个volatle的int类型的成员变量来表示同步状态,通过内置的FIFO队列来完成资源获取的排队工作将每条要去抢占资源的线程封装成一个Node节点来实现锁的分配,通过CAS完成对State值的修改。


static final class Node {

        static final Node SHARED = new Node();

        static final Node EXCLUSIVE = null;

        static final int CANCELLED =  1;

        static final int SIGNAL    = -1;

        static final int CONDITION = -2;

        static final int PROPAGATE = -3;

        volatile int waitStatus;

        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() {
        }

        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;
        }
    }
	
    private transient volatile Node head;

    private transient volatile Node tail;

    private volatile int state;

AQS同步队列基本结构:

1689045504902

AQS源码分析前置知识

AQS体系架构

1689058802991

AQS自身结构

static final class Node {

        static final Node SHARED = new Node();

        static final Node EXCLUSIVE = null;

        static final int CANCELLED =  1;

        static final int SIGNAL    = -1;

        static final int CONDITION = -2;

        static final int PROPAGATE = -3;

        volatile int waitStatus;

        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() {
        }

        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;
        }
    }
	
    private transient volatile Node head;

    private transient volatile Node tail;

    private volatile int state;

private volatile int state; 变量:

​ AQS的同步状态State成员变量,0临界资源可用,1临界资源被占用

CLH双向队列:

​ 通过自旋等待,state变量判断是否阻塞,从尾部入队,从头部出队

有阻塞就需要排队,实现排队必然需要队列,实现:state变量+CLH双端队列

内部类Node(AQS内部类)

AQS源码深度分析

Lock接口的实现类,基本都是通过【聚合】了一个【队列同步器】的子英完成线程问控制的

ReentrantLock的原理

1689059606246

private final Sync sync;
// 默认是创建非公平锁
public ReentrantLock() {
    sync = new NonfairSync();
}
// true是公平锁,false是非公平锁
public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

从最简单的lock方法开始看看公平和非公平

1689059856437

公平锁与非公平锁底层实际都是继承 Sync 这个类 Sync 又继承的AbstractQueuedSynchronizer

从底层看公平锁与非公平锁的区别实现
    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;

        /**
         * Performs lock.  Try immediate barge, backing up to normal
         * acquire on failure.
         */
        final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }
----------------------------------------------------------------------------------
    static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;

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

        /**
         * Fair version of tryAcquire.  Don't grant access unless
         * recursive call or no waiters or is first.
         */
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
    }

公平与非公平的底层区别:

​ lock() 方法:

​ 非公平锁

 if (compareAndSetState(0, 1))
     setExclusiveOwnerThread(Thread.currentThread());
 else
     acquire(1);
先使用cas获取临界区state 如果状态为0则获取锁成功,并将 占有锁设置为当前线程
如果cas失败表示临界区有线程在使用,则请求获得锁acquire

​ 公平锁

  final void lock() {
            acquire(1);
        }
直接尝试获得锁

​ acquire(1);方法:是父类AbstractQueuedSynchronizer 定义的方法 有自定义实现

public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

​ tryAcquire方法:是父类AbstractQueuedSynchronizer 定义的方法,但是抛出异常,强制子类实现

    protected boolean tryAcquire(int arg) {
        throw new UnsupportedOperationException();
    }

​ 非公平锁 NonfairSync:

	protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }

	final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

​ 公平锁

       protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

​ 区别:

​ 公平: if (!hasQueuedPredecessors() && compareAndSetState(0, acquires))

​ 非公平:if (compareAndSetState(0, acquires))

可以明显看出公平锁与非公平锁的lock()方法唯一的区别就在于公平锁在获取同步状态时多了一个限制条件:hasQueuedPredecessors()。hasQueuedPredecessors是公平锁加锁时判断等待队列中是否存在有效节点的方法

hasQueuedPredecessors()中判断了是否需要排队,导致公平锁和非公平锁的差异如下:
​ 公平锁:公平锁讲究先来先得,线程在获取锁时,如果这个锁的等待队列中已经有线程在等待,那么当前线程就会进入等待队列中;
​ 非公平锁:不管是否有等待队列,如果可以获取锁,则立刻占有锁对象。也就是说队列的第一个排队线程苏醒后,不一定就是排头的这个线程获得锁,它还是需要参加竞争锁(存在线程竞争的情况下),后来的线程可能不讲武德插队夺锁了。

以非公平锁ReentrantLock()为例解析AQS底层原理

三大流程走向

​ 1. tryAcquire(arg)

​ 2. addWaiter(Node.EXCLUSIVE)

​ 3. acquireQueued(addWaiter(Node.EXCLUSIVE), arg)

 /**
     * Acquires in exclusive mode, ignoring interrupts.  Implemented
     * by invoking at least once {@link #tryAcquire},
     * returning on success.  Otherwise the thread is queued, possibly
     * repeatedly blocking and unblocking, invoking {@link
     * #tryAcquire} until success.  This method can be used
     * to implement method {@link Lock#lock}.
     *
     * @param arg the acquire argument.  This value is conveyed to
     *        {@link #tryAcquire} but is otherwise uninterpreted and
     *        can represent anything you like.
     * 以独占模式获取,忽略中断。实现通过调用至少一次{@link #tryAcquire}成功归来。否则,线程可能会排队反复阻塞和解除阻塞,调用{@link#tryAcquire}直到成功。这种方法可以使用实现方法{@link Lock# Lock}。
     * @param参数获取参数。该值被传递给{@link #tryAcquire}但未被解释可以代表任何你喜欢的东西。
     */

public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
以银行窗口办理为场景说明
AQS属性方法说明
static final class Node {
	    // 线程以共享的方式等待锁
        static final Node SHARED = new Node();
	    // 线程正在以独占得方式使用锁
        static final Node EXCLUSIVE = null;
		// 当前线程获取锁的请求已经取消了
        static final int CANCELLED =  1;
		// 当前线程已经准备好了,就等资源释放锁了
        static final int SIGNAL    = -1;
		// 节点在等待队列中,节点线程等待唤醒
        static final int CONDITION = -2;
		// 当前线程处在 SHARED 该字段才会使用
        static final int PROPAGATE = -3;
		// 当前节点在队列中的状态 ---上面的状态都是 waitStatus 的枚举
        volatile int waitStatus;
		// 处于当前节点的线程
        volatile Thread thread;
       	 // 指向处于下一个 处于CONDITION状态的节点
        Node nextWaiter;

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

    	// 返回前驱节点 如果没有抛出npe
        final Node predecessor() throws NullPointerException {
            Node p = prev;
            if (p == null)
                throw new NullPointerException();
            else
                return p;
        }

        Node() {
        }

        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;
        }
    }
	// CLH队列的头节点
    private transient volatile Node head;
	// CLH队列的尾节点
    private transient volatile Node tail;
	// 临界资源的状态 0空闲,1已被抢占
    private volatile int state;
从银行办理业务开始解读源码

A BC三个顾客,去银行办理业务,A先到,此时窗口空无一人,他优先获得办理窗口的机会,办理业务。//A耗时严重,估计长期占有窗口

 ReentrantLock reentrantLock = new ReentrantLock();//非公平锁
        //A BC三个顾客,去银行办理业务,A先到,此时窗口空无一人,他优先获得办理窗口的机会,办理业务。//A耗时严重,估计长期占有窗口
        new Thread(() -> {
            reentrantLock.lock();
            try {
                System.out.println("----come in A");//暂停20分钟线程
                try {
                    TimeUnit.MINUTES.sleep(20);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } finally {
                reentrantLock.unlock();
            }
        }, "A").start();
        //B是第2个顾客,B一看到受理窗口被A占用,只能去候客区等待,进入AQS队列,等待着A办理完成,尝试去抢占受理窗口。
        new Thread(() -> {
            reentrantLock.lock();
            try {
                System.out.println("----come in B");
                try {
                    TimeUnit.MINUTES.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } finally {
                reentrantLock.unlock();
            }
        }, "B").start();
        //c是第3个顾客,c一看到受理窗口被A占用,只能去候客区等待,进入AQS队列,等待着A办理完成,尝试去抢占受理窗口,前面是B顾客,FIFO
        new Thread(() -> {
            reentrantLock.lock();
            try {
                System.out.println("----come in C");
                try {
                    TimeUnit.MINUTES.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } finally {
                reentrantLock.unlock();
            }
        }, "C").start();
    }
  1. A进来办理

​ compareAndSetState(0, 1) 成功,将独占线程设置为当前线程

        final void lock() {
            // A进入if块 设置临界资源状态为 1 并且将独占线程设置为当前线程
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

  1. B进来办理
final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
    // B进入else块
            else
                acquire(1);
        }

由于A耗时较长 B进来的时候A还没有结束 进入else块 进入acquire排队

    /*进入aquire 首先尝试获得锁*/
	public final void acquire(int arg) {
        // 5 tryAcquire(arg) 为false  !tryAcquire(arg)为 true进入 addWaiter(Node.EXCLUSIVE)
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    	}

        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
		// 4 尝试获得锁 返回false
        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            // 1 获取临界区状态,因为现在A正在办理,所以 c 为 1
            int c = getState();
            // 2 临界区状态是不是0 c为1 返回false
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            // 3 正在办理的线程是不是当前线程,返回false
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
		/*添加到等待队列*/
    	private Node addWaiter(Node mode) {
        /*创建队列新节点 mode为 Node.EXCLUSIVE(独占)*/
        Node node = new Node(Thread.currentThread(), mode);
        // Try the fast path of enq; backup to full enq on failure
        Node pred = tail;
        // 6 由于队列刚开始新建,尾节点为null 不进入if块
        if (pred != null) {
            node.prev = pred;
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        // 7入队,只在初始化的时候调用一次
        enq(node);
        return node;
    }
	/*第一个节点入队*/
    private Node enq(final Node node) {
        for (;;) {
            Node t = tail;
            /*第一次循环*/
            if (t == null) { // Must initialize
                // 8比较并设置为头节点。 unsafe.compareAndSwapObject(this, headOffset, null, update); 将头节点的偏移量设置为新建的节点 new Node()【哨兵节点】
                if (compareAndSetHead(new Node()))
                    // 9将头节点赋值给尾节点  
				/* head   ---->     +------------+ 
				*                   | new Node() | 
				*  tail   ---->     +------------+ 
				*/
                    tail = head;
            } else { /*第二次循环 t != null */ 
                // 10将要存入的节点的前驱节点设置成头节点
                node.prev = t;
                // 11设置尾节点期望尾节点是t,设置成node-->将当前插入的节点设置成尾节点
                if (compareAndSetTail(t, node)) {
                // 12将原来tail的后继节点设置为当前节点 返回尾节点,至此B线程 入队成功
				/* head   ---->     +------------+  <----prev   +------------+     
				 *                  | new Node() |              |   B线程    |    
				 *  tail            +------------+  next---->   +------------+ 
				 *   |                                                 ^
				 *   |_________________________________________________|
				 */
                    t.next = node;
                    return t;
                }
            }
        }
    /**
     * CAS head field. Used only by enq.
     */
    private final boolean compareAndSetHead(Node update) {
        return unsafe.compareAndSwapObject(this, headOffset, null, update);
    }
    /**
     * CAS tail field. Used only by enq.
     */
    private final boolean compareAndSetTail(Node expect, Node update) {
        return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
    }
  1. 三号线程C进来办理-- addWaiter(node),之前的流程都是相同的
/*添加到等待队列*/
    	private Node addWaiter(Node mode) {
        /*创建队列新节点 mode为 Node.EXCLUSIVE(独占)*/
        Node node = new Node(Thread.currentThread(), mode);
        // Try the fast path of enq; backup to full enq on failure
        Node pred = tail;
        // 1这里将pred = tail,所以pred为B节点,所以不为null
        if (pred != null) {
            // 2将C节点的前驱节点设置为B节点
            node.prev = pred;
            // 3设置尾节点指向,cas判断尾节点是否是 pred(B节点),将他设置为当前节点,至此C节点入队成功
            /* head   ---->     +---------+  <-prev  +--------+ <-prev +--------+   
             *                  | newNode |          | B线程  |         | C线程  |   
             *  tail            +---------+  next->  +--------+ next-> +--------+  
             *   |                                                          ^
             *   |----------------------------------------------------------|
             */
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        // 不进入 这个方法
        enq(node);
        return node;
    }
  1. acquireQueued(final Node node, int arg) 方法 以B为例
 /**
     * Acquires in exclusive uninterruptible mode for thread already in
     * queue. Used by condition wait methods as well as acquire.
     *
     * @param node the node 要入队的Node
     * @param arg the acquire argument 是1
     * @return {@code true} if interrupted while waiting 在等待时被中断则返回true
     * 自旋获得锁
     */
    final boolean acquireQueued(final Node node, int arg) {
        // 是否失败
        boolean failed = true;
        try {
            // 是否中断
            boolean interrupted = false;
            for (;;) {
                // 1获取当前节点的第一个节点 B进来就是获取头节点
                final Node p = node.predecessor();
                // 2B入队时  p == head 为true 继续进行   tryAcquire(1) 返回false
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                // 3将头节点和B节点传入 shouldParkAfterFailedAcquire(p, node) 
                // 10 执行  parkAndCheckInterrupt()-》 LockSupport.park(this); 将当前线程阻塞
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

    /**
     * Checks and updates status for a node that failed to acquire.
     * Returns true if thread should block. This is the main signal
     * control in all acquire loops.  Requires that pred == node.prev.
     *
     * @param pred node's predecessor holding status
     * @param node the node
     * @return {@code true} if thread should block
     *
     *检查并更新获取失败节点的状态。
	 *如果线程阻塞,返回true。这是主要信号
	*控制所有获取循环。要求pred == node.prev。
	
	    // 当前线程获取锁的请求已经取消了
        static final int CANCELLED =  1;
		// 当前线程已经准备好了,就等资源释放锁了
        static final int SIGNAL    = -1;
		// 节点在等待队列中,节点线程等待唤醒
        static final int CONDITION = -2;
		// 当前线程处在 SHARED 该字段才会使用
        static final int PROPAGATE = -3;
        // 当前节点在队列中的状态 ---上面的状态都是 waitStatus 的枚举
        volatile int waitStatus;
     */
    private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        // 4获取头节点的 waitStatus
        int ws = pred.waitStatus;
        // 5刚初始化头节点的waitStatus 默认为 0 进入else
        // 8 头节点的状态为 SIGNAL 进入方法快
        if (ws == Node.SIGNAL)
            /*
             * This node has already set status asking a release
             * to signal it, so it can safely park.
             */
            // 9返回true 进入  parkAndCheckInterrupt()
            return true;
        if (ws > 0) {
            /*
             * Predecessor was cancelled. Skip over predecessors and
             * indicate retry.
             */
            do {
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
            pred.next = node;
        } else {
            /*
             * waitStatus must be 0 or PROPAGATE.  Indicate that we
             * need a signal, but don't park yet.  Caller will need to
             * retry to make sure it cannot acquire before parking.
             */
            // waitStatus必须为0或PROPAGATE。表明我们需要一个信号,但不要立即将线程进行休眠。调用者将需要重试以确保在进入休眠状态之前无法获取所需资源。
            // 6将前驱节点的状态设置为 SIGNAL(-1) 表示当前线程已经准备好了,就等资源释放锁了
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        // 7返回false 重新进入 acquireQueued 循环
        return false;
    }

    /**
     * CAS waitStatus field of a node.
     */
    private static final boolean compareAndSetWaitStatus(Node node,
                                                         int expect,
                                                         int update) {
        return unsafe.compareAndSwapInt(node, waitStatusOffset,
                                        expect, update);
    }

    private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this);
        return Thread.interrupted();
    }
  1. 当线程A执行完任务后(unlock)后续线程如何占有锁
// 1 A线程进行unlock()
 reentrantLock.unlock();
 public void unlock() {
        sync.release(1);
    }

 public final boolean release(int arg) {
     // 2执行 tryRelease(1)
        if (tryRelease(arg)) {
            // 8获取头节点
            Node h = head;
            // 9头节点不为null 并且节点的状态为 -1 不为0
            if (h != null && h.waitStatus != 0)
                // 10执行unparkSuccessor
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

 protected final boolean tryRelease(int releases) {
     		// 3 当前线程正在使用资源所以  getState() ==1 并且 releases == 1 所以c == 0
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
     		// 4进入if
            if (c == 0) {
                free = true;
                // 5释放锁占有
                setExclusiveOwnerThread(null);
            }
     		// 6将临界区状态重新设置为 0 
            setState(c);
     		// 7返回true
            return free;
        }

    protected final void setState(int newState) {
        state = newState;
    }


    private void unparkSuccessor(Node node) {
        /*
         * If status is negative (i.e., possibly needing signal) try
         * to clear in anticipation of signalling.  It is OK if this
         * fails or if status is changed by waiting thread.
         */
        // 11获取头节点的waitstatus 为 -1
        int ws = node.waitStatus;
        if (ws < 0)
            // 12将头节点状态 设置为 0
            compareAndSetWaitStatus(node, ws, 0);

        /*
         * Thread to unpark is held in successor, which is normally
         * just the next node.  But if cancelled or apparently null,
         * traverse backwards from tail to find the actual
         * non-cancelled successor.
         */
        // 13获取头节点的后继节点 即 B
        Node s = node.next;
        // B的 waitStatus 为-1 不进入if
        if (s == null || s.waitStatus > 0) {
            s = null;
            for (Node t = tail; t != null && t != node; t = t.prev)
                if (t.waitStatus <= 0)
                    s = t;
        }
        // 14将 B线程 unpark
        if (s != null)
            LockSupport.unpark(s.thread);
    }

	
    final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                // 16 获取B的 前驱节点 即为head
                final Node p = node.predecessor();
                // 17 p == head 为true 并且执行 tryAcquire(arg) 将临界status设置为1 设置独占线程为当前线程并 返回 为true  ----> 现在B独占临界资源
                // 因为是非公平锁 线程释放锁以后其他线程都有可能获取锁 所以需要进行  tryAcquire(arg)
                if (p == head && tryAcquire(arg)) {
                    // 18将头节点指针指向 B,并设置 node.thread = null; node.prev = null;
                    setHead(node);
                    // 19将 头节点的next 指针断掉,帮助JVM回收头节点
                    // 至此哨兵节点(空节点)出队
                    p.next = null; // help GC
                    failed = false;
                    // 20返回false 流程结束
                    return interrupted;
                }
                // 15 B unpark之后 parkAndCheckInterrupt() 返回false
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

    private void setHead(Node node) {
        head = node;
        node.thread = null;
        node.prev = null;
    }

    private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this);
        return Thread.interrupted();
    }

  1. 如果有(一个/多个)线程在阻塞过程中要出队
 final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            // 1线程cancel,需要移除队列
            if (failed)
                cancelAcquire(node);
        }
    }

 private void cancelAcquire(Node node) {
        if (node == null)
            return;
		// 2清除node存放的线程
        node.thread = null;

        // 3跳过已经取消的其他前驱节点,如果有多个都取消,一直找到不是cancel状态的前驱节点,并将当前线程的前驱指向不是cancel状态的前驱节点
        Node pred = node.prev;
        while (pred.waitStatus > 0)
            node.prev = pred = pred.prev;
     	// 4获取非cancel状态的后继节点
        Node predNext = pred.next;

     	// 5将当前node的状态 设置为  CANCELLED
        node.waitStatus = Node.CANCELLED;

        // 6如果是最后一个节点,将tail 指向 当前node 的前驱节点,并且将非cancel状态的前驱节点的后继节点设置为当前节点的前驱节点
        if (node == tail && compareAndSetTail(node, pred)) {
            compareAndSetNext(pred, predNext, null);
        } else {
            // 7如果不是最后一个节点
            int ws;
            // 8不是头节点,并且满足出队条件
            if (pred != head &&
                ((ws = pred.waitStatus) == Node.SIGNAL ||
                 (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
                pred.thread != null) {
                // 9获取要出队节点的下一个节点
                Node next = node.next;
                if (next != null && next.waitStatus <= 0)
                    // 10将非cancel状态的前驱节点的后继节点设置为当前出队节点的后继节点
                    compareAndSetNext(pred, predNext, next);
            } else {
                unparkSuccessor(node);
            }
			// 11当前节点的下一个节点指向自己,帮助JVM回收
            node.next = node; // help GC
        }
    }

源码执行流程思维导图

未命名文件

posted @ 2023-07-12 14:47  奶油炒白菜  阅读(4)  评论(0编辑  收藏  举报