AQS源码
来源:互联网 发布:淘宝内裤好评语 编辑:程序博客网 时间:2024/06/03 15:37
import java.util.concurrent.TimeUnit;import java.util.ArrayList;import java.util.Collection;import java.util.Date;import sun.misc.Unsafe;public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable { private static final long serialVersionUID = 7373984972572414691L; protected AbstractQueuedSynchronizer() { } static final class Node { /** 标记表示一个节点在分享模式下等待 */ static final Node SHARED = new Node(); /**标记表示一个节点在独占模式下等待 */ static final Node EXCLUSIVE = null; /** 表示取消线程的值 */ static final int CANCELLED = 1; /** 信号值,表示需要unparking(唤醒线程)的信息 */ static final int SIGNAL = -1; /** 表示线程等待条件的值 */ static final int CONDITION = -2; /** * 表示获取下一个共享 * 无条件的传播(用于一级级释放资源) */ static final int PROPAGATE = -3; //等待状态(volatile修饰,可见性、原子性) volatile int waitStatus; //上一个节点 volatile Node prev; //下一个节点 volatile Node next; //节点入队列时的线程。初始化时构建,使用完成后清空 volatile Thread thread; //下一个等待的节点 Node nextWaiter; /** * 如果节点在共享模式中等待,则返回true */ 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; } } /** * 等待队列的头结点(懒加载方式实例化),除初始化外,只能使用setHead方法改变其值。 * 如果存在,它的状态保证不能取消 */ //头节点 private transient volatile Node head; /** * 等待队列的尾节点(懒加载方式实例化),只能通过尾部添加节点方式修改 */ //尾节点 private transient volatile Node tail; /** * 同步状态 */ private volatile int state; /** * 获取当前同步状态值 */ protected final int getState() { return state; } /** * 设置同步状态值 */ protected final void setState(int newState) { state = newState; } /** * 比较并设置同步状态值(此操作具备原子性,可见行 读写操作) * 比较:设置前比较当前的实际值和期望值是否一致,一致说明没有其它线程获得锁,则设置update值。 * 如果不一致,说明其它线程获得锁,正在修改值,则当前线程放弃更新值。 * @param expect 期望值 * @param update 要更新得新值 * @return 设置成功返回true. 当前的实际值和期望值不一致,当前线程放弃更新,返回false */ protected final boolean compareAndSetState(int expect, int update) { // See below for intrinsics setup to support this return unsafe.compareAndSwapInt(this, stateOffset, expect, update); } // Queuing utilities /** * The number of nanoseconds for which it is faster to spin * rather than to use timed park. A rough estimate suffices * to improve responsiveness with very short timeouts. */ static final long spinForTimeoutThreshold = 1000L; /** * 将节点插入到队列中,必要时进行初始化。 * @param node 新插入的节点 * @return 上一个节点 */ private Node enq(final Node node) { for (;;) {//无限循环 Node t = tail;//获取队列尾部节点 if (t == null) { //如果队列还没有初始化,则进行初始化,即创建一个空的头节点 Must initialize if (compareAndSetHead(new Node()))//创建头节点 tail = head; } else { //新创建的节点指向队列尾节点,毫无疑问并发情况下这里会有多个新创建的节点指向队列尾节点 node.prev = t; //基于这一步的CAS,不管前一步有多少新节点都指向了尾节点,这一步只有一个能真正入队成功,其他的都必须重新执行循环体 if (compareAndSetTail(t, node)) { t.next = node; return t;//该循环体唯一退出的操作,就是入队成功(否则就要无限重试) } } } } /** * 在当前线程给定的模式下创建节点 * @param 要创建的节点 模式: Node.EXCLUSIVE(独占模式), Node.SHARED(分享模式) * @return 返回新创建的节点 */ private Node addWaiter(Node mode) { Node node = new Node(Thread.currentThread(), mode);//基于当前线程创建新节点 // Try the fast path of enq; backup to full enq on failure Node pred = tail;//队列尾部节点 //这里为了提搞性能,首先执行一次快速入队操作,即直接尝试将新节点加入队尾 if (pred != null) {//存在尾部节点 node.prev = pred;//关联上一节点 //这里根据CAS的逻辑,即使并发操作也只能有一个线程成功并返回,其余的都要执行后面的入队操作。即enq()方法 if (compareAndSetTail(pred, node)) {//新创建的节点设置为队列的尾部节点 pred.next = node; return node; } } enq(node);//入队操作 return node; } /** * 设置队列头部节点 */ private void setHead(Node node) { head = node; node.thread = null; node.prev = null; } /** * 唤醒后继节点(如果存在) * @param node the node */ private void unparkSuccessor(Node node) { /** * waitStatus(节点状态对应的值) * CANCELLED:1 * SIGNAL :-1 * CONDITION :-2 * PROPAGATE :-3 * 状态0 初始化状态,也代表正在尝试去获取临界资源的线程所对应的Node的状态。 */ int ws = node.waitStatus;//节点同步状态 if (ws < 0) //把标记为设置为0,表示唤醒操作已经开始进行,提高并发环境下性能 compareAndSetWaitStatus(node, ws, 0); Node s = node.next; //如果当前节点的后继节点为null,或者已经被取消 if (s == null || s.waitStatus > 0) { s = null; //注意这个循环没有break,也就是说它是从后往前找,一直找到离当前节点最近的一个等待唤醒的节点 for (Node t = tail; t != null && t != node; t = t.prev) if (t.waitStatus <= 0) s = t; } //执行唤醒操作 if (s != null) LockSupport.unpark(s.thread);//唤醒离当前节点最近的一个等待唤醒的节点 } /** * 共享模式的释放(唤醒)操作 */ private void doReleaseShared() { //无限循环 for (;;) { //唤醒操作由头结点开始,注意这里的头节点已经是上面新设置的头结点了 //其实就是唤醒上面新获取到共享锁的节点的后继节点 Node h = head; if (h != null && h != tail) {//节点不为空而且不是尾部节点 int ws = h.waitStatus;//获取节点的同步状态 //表示后继节点需要被唤醒 if (ws == Node.SIGNAL) { //这里需要控制并发,因为入口有setHeadAndPropagate跟release两个,避免两次unpark //cvs 把标记为设置为0,表示唤醒操作已经开始进行,提高并发环境下性能 if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0)) continue; // loop to recheck cases //执行唤醒操作 unparkSuccessor(h); } //如果后继节点暂时不需要唤醒,则把当前节点状态设置为PROPAGATE确保以后可以传递下去 else if (ws == 0 && !compareAndSetWaitStatus(h, 0, Node.PROPAGATE)) continue; // loop on failed CAS } //如果头结点发生变化,比如说其他线程获取到了锁,为了使自己的唤醒动作可以传递,必须进行重试 if (h == head) //如果头结点没有发生变化,表示设置完成,退出循环 break; } } /** * 共享锁模式获取成功以后,调用此方法设置新的头结点以外还有一个传递动作 * @param 当前成功获取共享锁的节点 * @param tryAcquireShared方法的返回值,注意:它可能大于0也可能等于0 */ private void setHeadAndPropagate(Node node, int propagate) { Node h = head; // 要检查的老头部节点 //设置新的头节点,即把当前获取到锁的节点设置为头节点 //注:这里是获取到锁之后的操作,不需要并发控制 setHead(node); //这里意思有两种情况是需要执行唤醒操作 //1.propagate > 0 表示调用方指明了后继节点需要被唤醒 //2.头节点后面的节点需要被唤醒(waitStatus<0),不论是老的头结点还是新的头结点 if (propagate > 0 || h == null || h.waitStatus < 0 || (h = head) == null || h.waitStatus < 0) { Node s = node.next; //如果当前节点的后继节点是共享类型获取没有后继节点,则进行唤醒 //这里可以理解为除非明确指明不需要唤醒(后继等待节点是独占类型),否则都要唤醒 if (s == null || s.isShared()) doReleaseShared(); } } /** * 取消正在进行尝试获取的锁(获取失败节点的处理) * 其实能进入这里的就是tryAcquire()方法抛出异常,也就是说AQS框架针对开发人员自己实现的获取锁操作如果抛出异常,也做了妥善的处理 * @param node : 当前获取锁资源失败的节点 */ private void cancelAcquire(Node node) { //如果节点不存在则直接忽略 if (node == null) return; node.thread = null; // 跳过所有已经取消的前置节点,跟上面的那段跳转逻辑类似 Node pred = node.prev; while (pred.waitStatus > 0) node.prev = pred = pred.prev; //这个是前置节点的后继节点,由于上面可能的跳节点的操作,所以这里可不一定就是当前节点 Node predNext = pred.next; //把当前节点waitStatus置为取消,这样别的节点在处理时就会跳过该节点 node.waitStatus = Node.CANCELLED; //如果当前是尾节点,则直接删除,即出队 //注:这里不用关心CAS失败,因为即使并发导致失败,该节点也已经被成功删除 if (node == tail && compareAndSetTail(node, pred)) { compareAndSetNext(pred, predNext, null); } else { // If successor needs signal, try to set pred's next-link // so it will get one. Otherwise wake it up to propagate. int ws; if (pred != head && ((ws = pred.waitStatus) == Node.SIGNAL || (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) && pred.thread != null) { Node next = node.next; if (next != null && next.waitStatus <= 0) //这里的判断逻辑很绕,具体就是如果当前节点的前置节点不是头节点且它后面的节点等待它唤醒(waitStatus小于0), //再加上如果当前节点的后继节点没有被取消就把前置节点跟后置节点进行连接,相当于删除了当前节点 compareAndSetNext(pred, predNext, next); } else { //进入这里,要么当前节点的前置节点是头结点,要么前置节点的waitStatus是PROPAGATE,直接唤醒当前节点的后继节点 unparkSuccessor(node); } node.next = node; // help GC } } /** * 检查和更新未能获取的节点的状态。 * @param pred 前置节点 * @param node 当前线程节点 * @return 如果线程阻塞,则返回true */ private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) { int ws = pred.waitStatus;//获取前置节点状态 if (ws == Node.SIGNAL) //如果前置节点的waitStatus是Node.SIGNAL则返回true,然后会执行parkAndCheckInterrupt()方法进行挂起 return true; if (ws > 0) { //由waitStatus的几个取值可以判断这里表示前置节点被取消 do { node.prev = pred = pred.prev; } while (pred.waitStatus > 0); //这里我们由当前节点的前置节点开始,一直向前找最近的一个没有被取消的节点 //注,由于头结点head是通过new Node()创建,它的waitStatus为0,因此这里不会出现空指针问题,也就是说最多就是找到头节点上面的循环就退出了 pred.next = node; } else { //根据waitStatus的取值限定,这里waitStatus的值只能是0或者PROPAGATE,那么我们把前置节点的waitStatus设为Node.SIGNAL然后重新进入该方法进行判断 compareAndSetWaitStatus(pred, ws, Node.SIGNAL); } return false; } /** * 中断当前线程 */ static void selfInterrupt() { Thread.currentThread().interrupt(); } /** * 线程进入等待,然后检查是否中断唤醒。 * @return 中断唤醒,就返回true */ private final boolean parkAndCheckInterrupt() { //调用park()使线程进入waiting状态 LockSupport.park(this); //被唤醒之后,返回中断标记,即如果是正常唤醒则返回false,如果是由于中断醒来,就返回true return Thread.interrupted(); } /** * 使线程在等待队列中获取资源,一直获取到资源后才返回。如果在整个等待过程中被中断过,则返回true,否则返回false。 * @param node the node * @param arg 获得资源的参数 * @return 如果在整个等待过程中被中断过,则返回true,否则返回false */ final boolean acquireQueued(final Node node, int arg) { //锁资源获取失败标记位 boolean failed = true; try { //等待线程被中断标记位 boolean interrupted = false; //这个循环体执行的时机包括新节点入队和队列中等待节点被唤醒两个地方 for (;;) { //获取当前节点的前置节点 final Node p = node.predecessor(); //如果前置节点就是头结点,则尝试获取锁资源 //如果前驱是head,即该结点已成老二,那么便有资格去尝试获取资源(可能是老大释放完资源唤醒自己的,当然也可能被interrupt了)。 if (p == head && tryAcquire(arg)) { //当前节点获得锁资源以后设置为头节点,这里继续理解我上面说的那句话 //头结点就表示当前正占有锁资源的节点 setHead(node); // setHead中node.prev已置为null,此处再将head.next置为null,就是为了方便GC回收以前的head结点。也就意味着之前拿完资源的结点出队了! p.next = null; // help GC //表示锁资源成功获取,因此把failed置为false failed = false; //返回中断标记,表示当前节点是被正常唤醒还是被中断唤醒 return interrupted; } //如果没有获取锁成功(检查和更新未能获取的节点的状态),如果线程阻塞则进入挂起逻辑 if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } finally { if (failed) //最后会分析获取锁失败处理逻辑 cancelAcquire(node); } } /** * 大体上相当于前面的acquireQueued,关键的区别在于检测到interrupted后的处理, * acquireQueued简单的记录下中断曾经发生,然后继续去尝试获取锁,失败则休眠。 * 而doAcquireInterruptibly检测到中断则直接退出循环,抛出InterruptedException异常 * * @param arg 获得资源的参数 */ private void doAcquireInterruptibly(int arg) throws InterruptedException { //在当前线程创建一个独占模式节点 final Node node = addWaiter(Node.EXCLUSIVE); //锁资源获取失败标记位 boolean failed = true; try { for (;;) { //获取当前节点的前置节点 final Node p = node.predecessor(); //如果前置节点就是头结点,则尝试获取锁资源 //如果前驱是head,即该结点已成老二,那么便有资格去尝试获取资源(可能是老大释放完资源唤醒自己的,当然也可能被interrupt了)。 if (p == head && tryAcquire(arg)) { //头结点就表示当前正占有锁资源的节点 setHead(node); // setHead中node.prev已置为null,此处再将head.next置为null,就是为了方便GC回收以前的head结点。也就意味着之前拿完资源的结点出队了! p.next = null; // help GC //表示锁资源成功获取,因此把failed置为false failed = false; return; } //检查和更新未能获取的节点的状态。如果线程阻塞则进入挂起逻辑 if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) throw new InterruptedException();//抛出异常 } } finally { if (failed) //最后会分析获取锁失败处理逻辑 cancelAcquire(node); } } /** * 在限定时间内获取独占锁 * * @param arg 获取资源参数 * @param nanosTimeout 最大的限定事件 * @return 获取成功返回true */ private boolean doAcquireNanos(int arg, long nanosTimeout) throws InterruptedException { if (nanosTimeout <= 0L)//时间小于等于0 ,直接返回false,没有获得锁 return false; //计算最后期限 final long deadline = System.nanoTime() + nanosTimeout; //创建独占锁节点,加入队列尾部 final Node node = addWaiter(Node.EXCLUSIVE); //锁资源获取失败标记位 boolean failed = true; try { for (;;) { //获取当前节点的前置节点 final Node p = node.predecessor(); //如果前置节点就是头结点,则尝试获取锁资源 //如果前驱是head,即该结点已成老二,那么便有资格去尝试获取资源(可能是老大释放完资源唤醒自己的,当然也可能被interrupt了)。 if (p == head && tryAcquire(arg)) { //头结点就表示当前正占有锁资源的节点 setHead(node); // setHead中node.prev已置为null,此处再将head.next置为null,就是为了方便GC回收以前的head结点。也就意味着之前拿完资源的结点出队了! p.next = null; // help GC //表示锁资源成功获取,因此把failed置为false failed = false; return true;//直接返回获取锁 } //计算剩余时间 nanosTimeout = deadline - System.nanoTime(); if (nanosTimeout <= 0L)//超时则不再尝试获取锁,直接返回false return false; //检查和更新未能获取的节点的状态。如果线程阻塞则 比较纳秒时间 //如果没有超时,则等待nanosTimeout纳秒 //注:该线程会直接从LockSupport.parkNanos中返回 if (shouldParkAfterFailedAcquire(p, node) && nanosTimeout > spinForTimeoutThreshold) //spinForTimeoutThreshold 提高很短的超时的响应 LockSupport.parkNanos(this, nanosTimeout); if (Thread.interrupted())//如果当前线程被中断则泡异常 throw new InterruptedException(); } } finally { if (failed) //最后会分析获取锁失败处理逻辑 cancelAcquire(node); } } /** * 用于将当前线程加入等待队列尾部休息,直到其他线程释放资源唤醒自己,自己成功拿到相应量的资源后才返回 * @param arg the acquire argument */ private void doAcquireShared(int arg) { //创建共享锁节点,加入队列尾部 final Node node = addWaiter(Node.SHARED); //锁资源获取失败标记位 boolean failed = true; try { //等待过程中是否被中断过的标志 boolean interrupted = false; for (;;) { //获取当前节点的前置节点 final Node p = node.predecessor(); //如果前置节点就是头结点,则尝试获取锁资源,如果到head的下一个,因为head是拿到资源的线程,此时node被唤醒,很可能是head用完资源来唤醒自己的 if (p == head) { //如果前驱是head,即该结点已成老二,那么便有资格去尝试获取资源(可能是老大释放完资源唤醒自己的,当然也可能被interrupt了)。 int r = tryAcquireShared(arg); if (r >= 0) { setHeadAndPropagate(node, r);//将head指向自己,还有剩余资源可以再唤醒之后的线程 // setHead中node.prev已置为null,此处再将head.next置为null,就是为了方便GC回收以前的head结点。也就意味着之前拿完资源的结点出队了! p.next = null; // help GC if (interrupted)//如果等待过程中被打断过,此时将中断补上。 selfInterrupt(); failed = false; return; } } //判断状态,寻找安全点,进入waiting状态,等着被unpark()或interrupt() if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } finally { if (failed) //最后会分析获取锁失败处理逻辑 cancelAcquire(node); } } /** * 在可中断模式下获取资源 * @param arg the acquire argument */ private void doAcquireSharedInterruptibly(int arg) throws InterruptedException { //创建共享节点,加入队列尾部 final Node node = addWaiter(Node.SHARED); //锁资源获取失败标记位 boolean failed = true; try { for (;;) { //获取当前节点的前置节点 final Node p = node.predecessor(); //如果前置节点就是头结点,则尝试获取锁资源,如果到head的下一个,因为head是拿到资源的线程,此时node被唤醒,很可能是head用完资源来唤醒自己的 if (p == head) { //如果前驱是head,即该结点已成老二,那么便有资格去尝试获取资源(可能是老大释放完资源唤醒自己的,当然也可能被interrupt了)。 int r = tryAcquireShared(arg); if (r >= 0) { //将head指向自己,还有剩余资源可以再唤醒之后的线程 setHeadAndPropagate(node, r); // setHead中node.prev已置为null,此处再将head.next置为null,就是为了方便GC回收以前的head结点。也就意味着之前拿完资源的结点出队了! p.next = null; // help GC //表示锁资源成功获取,因此把failed置为false failed = false; return; } } //判断状态,寻找安全点,进入waiting状态,等着被unpark()或interrupt() if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) throw new InterruptedException(); } } finally { if (failed) //最后会分析获取锁失败处理逻辑 cancelAcquire(node); } } /** * 用于在一定时间范围内 将当前线程加入等待队列尾部休息,直到其他线程释放资源唤醒自己,自己成功拿到相应量的资源后才返回 * 和doAcquireShared差不多 * @param arg the acquire argument * @param nanosTimeout 等待的最长时间 * @return {@code true} if acquired */ private boolean doAcquireSharedNanos(int arg, long nanosTimeout) throws InterruptedException { if (nanosTimeout <= 0L) return false; //计算最后期限 final long deadline = System.nanoTime() + nanosTimeout; //创建共享节点,加入队列尾部 final Node node = addWaiter(Node.SHARED); //锁资源获取失败标记位 boolean failed = true; try { for (;;) { //获取当前节点的前置节点 final Node p = node.predecessor(); //如果前置节点就是头结点,则尝试获取锁资源,如果到head的下一个,因为head是拿到资源的线程,此时node被唤醒,很可能是head用完资源来唤醒自己的 if (p == head) { //如果前驱是head,即该结点已成老二,那么便有资格去尝试获取资源(可能是老大释放完资源唤醒自己的,当然也可能被interrupt了)。 int r = tryAcquireShared(arg); if (r >= 0) { //将head指向自己,还有剩余资源可以再唤醒之后的线程 setHeadAndPropagate(node, r); // setHead中node.prev已置为null,此处再将head.next置为null,就是为了方便GC回收以前的head结点。也就意味着之前拿完资源的结点出队了! p.next = null; // help GC //表示锁资源成功获取,因此把failed置为false failed = false; return true;//返回true,表示已获得锁 } } //计算剩余时间 nanosTimeout = deadline - System.nanoTime(); if (nanosTimeout <= 0L) return false; //检查和更新未能获取的节点的状态。如果线程阻塞则 比较纳秒时间 //如果没有超时,则等待nanosTimeout纳秒 //注:该线程会直接从LockSupport.parkNanos中返回 if (shouldParkAfterFailedAcquire(p, node) && nanosTimeout > spinForTimeoutThreshold) //spinForTimeoutThreshold 提高很短的超时的响应 LockSupport.parkNanos(this, nanosTimeout); if (Thread.interrupted())//如果当前线程被中断则泡异常 throw new InterruptedException(); } } finally { if (failed) //最后会分析获取锁失败处理逻辑 cancelAcquire(node); } } /**************************************************/ //什么?直接throw异常?说好的功能呢?好吧,还记得概述里讲的AQS只是一个框架,具体资源的获取/释放方式交由自定义同步器去实现吗?就是这里了!!! // AQS这里只定义了一个接口,具体资源的获取交由自定义同步器去实现了(通过state的get/set/CAS)!!!至于能不能重入,能不能加塞, // 那就看具体的自定义同步器怎么去设计了!!!当然,自定义同步器在进行资源访问时要考虑线程安全的影响。 //这里之所以没有定义成abstract,是因为独占模式下只用实现tryAcquire-tryRelease, // 而共享模式下只用实现tryAcquireShared-tryReleaseShared。如果都定义成abstract,那么每个模式也要去实现另一模式下的接口。 // 说到底,Doug Lea还是站在咱们开发者的角度,尽量减少不必要的工作量。 /************************************************/ /** * 尝试去获取独占资源。如果获取成功,则直接返回true,否则直接返回false */ protected boolean tryAcquire(int arg) { throw new UnsupportedOperationException(); } /** * 独占方式。尝试释放资源,成功则返回true,失败则返回false */ protected boolean tryRelease(int arg) { throw new UnsupportedOperationException(); } /** * 共享方式。尝试获取资源。负数表示失败;0表示成功,但没有剩余可用资源;正数表示成功,且有剩余资源 */ protected int tryAcquireShared(int arg) { throw new UnsupportedOperationException(); } /** 共享方式。尝试释放资源,如果释放后允许唤醒后续等待结点返回true,否则返回false */ protected boolean tryReleaseShared(int arg) { throw new UnsupportedOperationException(); } /** 该线程是否正在独占资源。只有用到condition才需要去实现它 */ protected boolean isHeldExclusively() { throw new UnsupportedOperationException(); } /** 此方法是独占模式下线程获取共享资源的顶层入口。如果获取到资源,线程直接返回, 否则进入等待队列,直到获取到资源为止,且整个过程忽略中断的影响。这也正是lock()的语义,当然不仅仅只限于lock()。 获取到资源后,线程就可以去执行其临界区代码了 */ public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); } /** * 独占模式获取锁,如果在获取锁的过程中线程被中断,则直接抛出中断异常 */ public final void acquireInterruptibly(int arg) throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); if (!tryAcquire(arg)) doAcquireInterruptibly(arg); } /** 尝试在指定纳秒时间内获取独占锁,如果被中断则抛出中断异常 */ public final boolean tryAcquireNanos(int arg, long nanosTimeout) throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); return tryAcquire(arg) || doAcquireNanos(arg, nanosTimeout); } /** 释放锁资源 */ public final boolean release(int arg) { if (tryRelease(arg)) { Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h); return true; } return false; } /** 共享模式获取锁,不响应中断,如果发生中断只会把当前线程的中断状态设置为true */ public final void acquireShared(int arg) { if (tryAcquireShared(arg) < 0) doAcquireShared(arg); } /** 共享模式获取锁,如果在获取锁的过程中线程被中断,则直接抛出中断异常 */ public final void acquireSharedInterruptibly(int arg) throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); if (tryAcquireShared(arg) < 0) doAcquireSharedInterruptibly(arg); } /** 尝试在指定纳秒时间内获取共享锁,如果被中断则抛出中断异常 */ public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout) throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); return tryAcquireShared(arg) >= 0 || doAcquireSharedNanos(arg, nanosTimeout); } /** 释放锁资源 */ public final boolean releaseShared(int arg) { if (tryReleaseShared(arg)) { doReleaseShared(); return true; } return false; } // Queue inspection methods /** 查询是否有线程正在等待获取指定的对象监视器 */ public final boolean hasQueuedThreads() { return head != tail; } /** 查询队列是否被多个acquire请求竞争过(导致某个线程阻塞过)。为什么head 不为null就能证明?有竞争就会入队列此时head不为null,但是任务执行完了呢? 通过上面的代码知道,head是由队列里刚获得到锁的线程设置的 (把自己设置成head),即使任务执行完也不会修改head,只能由下个入队的线程设置,这样head就永远不会为空了。 */ public final boolean hasContended() { return head != null; } /** 返回队列里第一个没有获取到锁的线程,如果head等于tail说明队列里没有线程在等待,直接返回null;否则,调用fullGetFirstQueuedThread。 */ public final Thread getFirstQueuedThread() { // handle only fast path, else relay return (head == tail) ? null : fullGetFirstQueuedThread(); } /** * Version of getFirstQueuedThread called when fastpath fails */ private Thread fullGetFirstQueuedThread() { /* * The first node is normally head.next. Try to get its * thread field, ensuring consistent reads: If thread * field is nulled out or s.prev is no longer head, then * some other thread(s) concurrently performed setHead in * between some of our reads. We try this twice before * resorting to traversal. */ // 一般来说这个线程就是head->next,需要保证在并发情况下读一致性: // 1. (h = head) != null // 2. (s = h.next) != null // 3. s.prev = head // 4. (st = s.thread) != null // 假设2、3中间被并发的插入了一个setHead方法,执行3时发现s.prev为空了 // 因此,这里需要再试一次(第二次其实也有可能会失败,不过概率已经很小 // 了,就像连续被雷劈两次一样;即使第二次也失败了,还有后面最后一道安 // 全措施,从tail开始向前遍历寻找)。 Node h, s; Thread st; if (((h = head) != null && (s = h.next) != null && s.prev == head && (st = s.thread) != null) || ((h = head) != null && (s = h.next) != null && s.prev == head && (st = s.thread) != null)) return st; /* * Head's next field might not have been set yet, or may have * been unset after setHead. So we must check to see if tail * is actually first node. If not, we continue on, safely * traversing from tail back to head to find first, * guaranteeing termination. */ // head.next也有可能被并发修改,比如上面的1、2中间插入了一个acquireQueued // 方法,执行完setHeader方法后将head.next置为null,这样条件2就不成立了, // 因此,就进入下面的最后一道程序了。 Node t = tail; Thread firstThread = null; while (t != null && t != head) { Thread tt = t.thread; if (tt != null) firstThread = tt; t = t.prev; } return firstThread; } /** 判断线程是否在队列里(包含头节点了),跟getFirstQueuedThread不一样,没有先从head开始找,直接从tail开始反向搜索,很直接。 因为getFirstQueuedThread要找的是第一个,从head开始找效率比较高,从tail开始反向遍历是因为没有其他更好的方法了。 isQueued不一样,它是找一个节点,反正都要遍历一遍,从head或tail都一样,时间复杂度都是O(n)。 */ public final boolean isQueued(Thread thread) { if (thread == null) throw new NullPointerException(); for (Node p = tail; p != null; p = p.prev) if (p.thread == thread) return true; return false; } /** 队列里第一个等待的结点是否是独占模式(不知道这里为啥没考虑并发情况,没有从tail开始遍历) */ final boolean apparentlyFirstQueuedIsExclusive() { Node h, s; return (h = head) != null && (s = h.next) != null && !s.isShared() && s.thread != null; } /** 通过判断"当前线程"是不是在CLH队列的队首,来返回AQS中是不是有比“当前线程”等待更久的线程 * @since 1.7 */ public final boolean hasQueuedPredecessors() { // The correctness of this depends on head being initialized // before tail and on head.next being accurate if the current // thread is first in queue. Node t = tail; // Read fields in reverse initialization order Node h = head; Node s; return h != t && ((s = h.next) == null || s.thread != Thread.currentThread()); } // Instrumentation and monitoring methods /** * 队列长度,不包括已经取消的和头节点,因为它俩的thread域都为null。 */ public final int getQueueLength() { int n = 0; for (Node p = tail; p != null; p = p.prev) { if (p.thread != null) ++n; } return n; } /** 返回一个 collection,它包含可能正等待获取此锁的线程 */ public final Collection<Thread> getQueuedThreads() { ArrayList<Thread> list = new ArrayList<Thread>(); for (Node p = tail; p != null; p = p.prev) { Thread t = p.thread; if (t != null) list.add(t); } return list; } /** * 返回包含可能正以独占模式等待获取的线程 collection */ public final Collection<Thread> getExclusiveQueuedThreads() { ArrayList<Thread> list = new ArrayList<Thread>(); for (Node p = tail; p != null; p = p.prev) { if (!p.isShared()) { Thread t = p.thread; if (t != null) list.add(t); } } return list; } /** * 返回包含可能正以共享模式等待获取的线程 collection */ public final Collection<Thread> getSharedQueuedThreads() { ArrayList<Thread> list = new ArrayList<Thread>(); for (Node p = tail; p != null; p = p.prev) { if (p.isShared()) { Thread t = p.thread; if (t != null) list.add(t); } } return list; } /** * Returns a string identifying this synchronizer, as well as its state. * The state, in brackets, includes the String {@code "State ="} * followed by the current value of {@link #getState}, and either * {@code "nonempty"} or {@code "empty"} depending on whether the * queue is empty. * * @return a string identifying this synchronizer, as well as its state */ public String toString() { int s = getState(); String q = hasQueuedThreads() ? "non" : ""; return super.toString() + "[State = " + s + ", " + q + "empty queue]"; } // Internal support methods for Conditions /** * 判断该节点是否在CLH队列中 */ final boolean isOnSyncQueue(Node node) { if (node.waitStatus == Node.CONDITION || node.prev == null) return false; if (node.next != null) // If has successor, it must be on queue return true; return findNodeFromTail(node); } /** * 从尾部查找node节点 */ private boolean findNodeFromTail(Node node) { Node t = tail; for (;;) { if (t == node) return true; if (t == null) return false; t = t.prev; } } /** * 将一个节点从condition队列转换到Sync队列 */ final boolean transferForSignal(Node node) { //所谓的Condition队列和Sync队列就在于waitStatus值 if (!compareAndSetWaitStatus(node, Node.CONDITION, 0)) return false; Node p = enq(node); int ws = p.waitStatus; if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL)) LockSupport.unpark(node.thread); return true; } /** * 函数表明在signal之前被中断还是之后被中断,依据就是node.waitStatus域的值, * 如果此时该域的值还是CONDITION,说明还没有被唤醒;否则,肯定就被唤醒过了 */ final boolean transferAfterCancelledWait(Node node) { if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) { enq(node); return true; } while (!isOnSyncQueue(node)) Thread.yield(); return false; } /** * Invokes release with current state value; returns saved state. * fullyRelease先获取state的值,把它作为参数调用AQS的release方法,并返回state。如果release失败或抛异常,则取消node,抛出异常。 */ final int fullyRelease(Node node) { boolean failed = true; try { int savedState = getState(); if (release(savedState)) { failed = false; return savedState; } else { throw new IllegalMonitorStateException(); } } finally { if (failed) node.waitStatus = Node.CANCELLED; } } // Instrumentation methods for conditions /** * Queries whether the given ConditionObject * uses this synchronizer as its lock. * * @param condition the condition * @return {@code true} if owned * @throws NullPointerException if the condition is null */ public final boolean owns(ConditionObject condition) { return condition.isOwnedBy(this); } /** * Queries whether any threads are waiting on the given condition * associated with this synchronizer. Note that because timeouts * and interrupts may occur at any time, a {@code true} return * does not guarantee that a future {@code signal} will awaken * any threads. This method is designed primarily for use in * monitoring of the system state. * * @param condition the condition * @return {@code true} if there are any waiting threads * @throws IllegalMonitorStateException if exclusive synchronization * is not held * @throws IllegalArgumentException if the given condition is * not associated with this synchronizer * @throws NullPointerException if the condition is null */ public final boolean hasWaiters(ConditionObject condition) { if (!owns(condition)) throw new IllegalArgumentException("Not owner"); return condition.hasWaiters(); } /** * 返回等待与此锁定相关的给定条件condition的线程估计数 */ public final int getWaitQueueLength(ConditionObject condition) { if (!owns(condition)) throw new IllegalArgumentException("Not owner"); return condition.getWaitQueueLength(); } /** * 返回一个 collection,该 collection 包含那些正在与此同步器关联的给定条件上等待的线程。 */ public final Collection<Thread> getWaitingThreads(ConditionObject condition) { if (!owns(condition)) throw new IllegalArgumentException("Not owner"); return condition.getWaitingThreads(); } /** * Condition implementation for a {@link * AbstractQueuedSynchronizer} serving as the basis of a {@link * Lock} implementation. * * <p>Method documentation for this class describes mechanics, * not behavioral specifications from the point of view of Lock * and Condition users. Exported versions of this class will in * general need to be accompanied by documentation describing * condition semantics that rely on those of the associated * {@code AbstractQueuedSynchronizer}. * * <p>This class is Serializable, but all fields are transient, * so deserialized conditions have no waiters. */ public class ConditionObject implements Condition, java.io.Serializable { private static final long serialVersionUID = 1173984872572414699L; /** First node of condition queue. */ //Condition队列的头指针 private transient Node firstWaiter; /** Last node of condition queue. */ //Condition队列的尾指针 private transient Node lastWaiter; /** * Creates a new {@code ConditionObject} instance. */ public ConditionObject() { } // Internal methods /** * 添加一个等待Node到队列中 */ private Node addConditionWaiter() { Node t = lastWaiter; // 如果尾节点被取消了,清理掉 if (t != null && t.waitStatus != Node.CONDITION) { unlinkCancelledWaiters(); t = lastWaiter; } // 新建一个Condition状态的节点,并将其加在尾部 Node node = new Node(Thread.currentThread(), Node.CONDITION); if (t == null) firstWaiter = node; else t.nextWaiter = node; lastWaiter = node; return node; } /** * 真正的释放信号(唤醒) */ private void doSignal(Node first) { do { //将first的nextWaiter设为null if ( (firstWaiter = first.nextWaiter) == null) lastWaiter = null; first.nextWaiter = null; // 如果转换队列不成功且等待队列不为null,继续do } while (!transferForSignal(first) && (first = firstWaiter) != null); } /** * 遍历所有节点,使其加入到Sync队列 */ private void doSignalAll(Node first) { lastWaiter = firstWaiter = null; do { Node next = first.nextWaiter; first.nextWaiter = null; transferForSignal(first); first = next; } while (first != null); } /** * 删除Condition队列中被cancel的节点 */ private void unlinkCancelledWaiters() { Node t = firstWaiter;//头指针 Node trail = null; while (t != null) { Node next = t.nextWaiter;//下一个等待的节点 if (t.waitStatus != Node.CONDITION) { t.nextWaiter = null; if (trail == null) firstWaiter = next; else trail.nextWaiter = next; if (next == null) lastWaiter = trail; } else trail = t; t = next; } } // public methods /** * 唤醒Condition队列的头节点持有的线程 */ public final void signal() { if (!isHeldExclusively()) throw new IllegalMonitorStateException(); Node first = firstWaiter; if (first != null) doSignal(first); } /** * 唤醒Condition队列的所有等待线程 */ public final void signalAll() { if (!isHeldExclusively()) throw new IllegalMonitorStateException(); Node first = firstWaiter; if (first != null) doSignalAll(first); } /** * 线程在等待的时候,线程若主动抛出异常,则相对应的程序也不会抛出异常。 */ public final void awaitUninterruptibly() { Node node = addConditionWaiter(); int savedState = fullyRelease(node); boolean interrupted = false; while (!isOnSyncQueue(node)) { LockSupport.park(this); if (Thread.interrupted()) interrupted = true; } if (acquireQueued(node, savedState) || interrupted) selfInterrupt(); } /** 表示发生了中断*/ private static final int REINTERRUPT = 1; /**在await状态下发生中断 */ private static final int THROW_IE = -1; /** * Checks for interrupt, returning THROW_IE if interrupted * before signalled, REINTERRUPT if after signalled, or * 0 if not interrupted. */ private int checkInterruptWhileWaiting(Node node) { return Thread.interrupted() ? (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) : 0; } /** * Throws InterruptedException, reinterrupts current thread, or * does nothing, depending on mode. */ private void reportInterruptAfterWait(int interruptMode) throws InterruptedException { if (interruptMode == THROW_IE) throw new InterruptedException(); else if (interruptMode == REINTERRUPT) selfInterrupt(); } /** * 可以响应线程中断命令 * </ol> */ public final void await() throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); Node node = addConditionWaiter();//当前线程放入Condition队列的尾 int savedState = fullyRelease(node);//释放当前线程持有的锁 int interruptMode = 0; while (!isOnSyncQueue(node)) {//循环检测线程的状态 LockSupport.park(this); if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) break; } if (acquireQueued(node, savedState) && interruptMode != THROW_IE) interruptMode = REINTERRUPT; if (node.nextWaiter != null) // clean up if cancelled unlinkCancelledWaiters(); if (interruptMode != 0) reportInterruptAfterWait(interruptMode); } /** * 限时的在条件变量上等待 */ public final long awaitNanos(long nanosTimeout) throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); Node node = addConditionWaiter(); int savedState = fullyRelease(node); final long deadline = System.nanoTime() + nanosTimeout; int interruptMode = 0; while (!isOnSyncQueue(node)) { if (nanosTimeout <= 0L) { transferAfterCancelledWait(node); break; } if (nanosTimeout >= spinForTimeoutThreshold) LockSupport.parkNanos(this, nanosTimeout); if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) break; nanosTimeout = deadline - System.nanoTime(); } if (acquireQueued(node, savedState) && interruptMode != THROW_IE) interruptMode = REINTERRUPT; if (node.nextWaiter != null) unlinkCancelledWaiters(); if (interruptMode != 0) reportInterruptAfterWait(interruptMode); return deadline - System.nanoTime(); } /** * 指定结束时刻的在条件变量上等待 */ public final boolean awaitUntil(Date deadline) throws InterruptedException { long abstime = deadline.getTime(); if (Thread.interrupted()) throw new InterruptedException(); Node node = addConditionWaiter(); int savedState = fullyRelease(node); boolean timedout = false; int interruptMode = 0; while (!isOnSyncQueue(node)) { if (System.currentTimeMillis() > abstime) { timedout = transferAfterCancelledWait(node); break; } LockSupport.parkUntil(this, abstime); if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) break; } if (acquireQueued(node, savedState) && interruptMode != THROW_IE) interruptMode = REINTERRUPT; if (node.nextWaiter != null) unlinkCancelledWaiters(); if (interruptMode != 0) reportInterruptAfterWait(interruptMode); return !timedout; } /** * Implements timed condition wait. * <ol> * <li> If current thread is interrupted, throw InterruptedException. * <li> Save lock state returned by {@link #getState}. * <li> Invoke {@link #release} with saved state as argument, * throwing IllegalMonitorStateException if it fails. * <li> Block until signalled, interrupted, or timed out. * <li> Reacquire by invoking specialized version of * {@link #acquire} with saved state as argument. * <li> If interrupted while blocked in step 4, throw InterruptedException. * <li> If timed out while blocked in step 4, return false, else true. * </ol> */ public final boolean await(long time, TimeUnit unit) throws InterruptedException { long nanosTimeout = unit.toNanos(time); if (Thread.interrupted()) throw new InterruptedException(); Node node = addConditionWaiter(); int savedState = fullyRelease(node); final long deadline = System.nanoTime() + nanosTimeout; boolean timedout = false; int interruptMode = 0; while (!isOnSyncQueue(node)) { if (nanosTimeout <= 0L) { timedout = transferAfterCancelledWait(node); break; } if (nanosTimeout >= spinForTimeoutThreshold) LockSupport.parkNanos(this, nanosTimeout); if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) break; nanosTimeout = deadline - System.nanoTime(); } if (acquireQueued(node, savedState) && interruptMode != THROW_IE) interruptMode = REINTERRUPT; if (node.nextWaiter != null) unlinkCancelledWaiters(); if (interruptMode != 0) reportInterruptAfterWait(interruptMode); return !timedout; } // support for instrumentation /** * Returns true if this condition was created by the given * synchronization object. * * @return {@code true} if owned */ final boolean isOwnedBy(AbstractQueuedSynchronizer sync) { return sync == AbstractQueuedSynchronizer.this; } /** * 根据Condition条件去查询是否有线程正在等待获取此锁 */ protected final boolean hasWaiters() { if (!isHeldExclusively()) throw new IllegalMonitorStateException(); for (Node w = firstWaiter; w != null; w = w.nextWaiter) { if (w.waitStatus == Node.CONDITION) return true; } return false; } /** * 返回等待与此锁定相关的给定条件condition的线程估计数 */ protected final int getWaitQueueLength() { if (!isHeldExclusively()) throw new IllegalMonitorStateException(); int n = 0; for (Node w = firstWaiter; w != null; w = w.nextWaiter) { if (w.waitStatus == Node.CONDITION) ++n; } return n; } /** * 返回一个 collection,该 collection 包含那些正在与此同步器关联的给定条件上等待的线程。 */ protected final Collection<Thread> getWaitingThreads() { if (!isHeldExclusively()) throw new IllegalMonitorStateException(); ArrayList<Thread> list = new ArrayList<Thread>(); for (Node w = firstWaiter; w != null; w = w.nextWaiter) { if (w.waitStatus == Node.CONDITION) { Thread t = w.thread; if (t != null) list.add(t); } } return list; } } /** * Setup to support compareAndSet. We need to natively implement * this here: For the sake of permitting future enhancements, we * cannot explicitly subclass AtomicInteger, which would be * efficient and useful otherwise. So, as the lesser of evils, we * natively implement using hotspot intrinsics API. And while we * are at it, we do the same for other CASable fields (which could * otherwise be done with atomic field updaters). */ private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final long stateOffset; private static final long headOffset; private static final long tailOffset; private static final long waitStatusOffset; private static final long nextOffset; static { try { stateOffset = unsafe.objectFieldOffset (AbstractQueuedSynchronizer.class.getDeclaredField("state")); headOffset = unsafe.objectFieldOffset (AbstractQueuedSynchronizer.class.getDeclaredField("head")); tailOffset = unsafe.objectFieldOffset (AbstractQueuedSynchronizer.class.getDeclaredField("tail")); waitStatusOffset = unsafe.objectFieldOffset (Node.class.getDeclaredField("waitStatus")); nextOffset = unsafe.objectFieldOffset (Node.class.getDeclaredField("next")); } catch (Exception ex) { throw new Error(ex); } } /** * 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); } /** * CAS waitStatus field of a node. */ private static final boolean compareAndSetWaitStatus(Node node, int expect, int update) { return unsafe.compareAndSwapInt(node, waitStatusOffset, expect, update); } /** * CAS next field of a node. */ private static final boolean compareAndSetNext(Node node, Node expect, Node update) { return unsafe.compareAndSwapObject(node, nextOffset, expect, update); }}
参考文章:
深入浅出AQS之共享锁模式
深入浅出AQS之独占锁模式
深入浅出AQS之组件概览
Java并发之AQS详解
Java 1.6 AbstractQueuedSynchronizer源码解析
ConditionObject源码阅读
Java多线程之JUC包:Condition源码学习笔记
阅读全文
0 0
- AQS源码
- AQS源码分析
- Java AQS源码分析
- AQS(AbstractQueuedSynchronizer)源码分析
- AQS源码分析
- AQS原理与源码
- AQS源码分析
- AQS源码分析
- AQS源码分析
- AQS源码分析
- JUC - AbstractQueuedSynchronizer(AQS) 源码分析
- AQS源码分析之ConditionObject
- AbstractQueuedSynchronizer(AQS)源码解析上
- AbstractQueuedSynchronizer(AQS)源码解析下
- AbstractQueuedSynchronizer(AQS)源码解析-续
- AQS
- AQS
- AQS
- 【数据结构】搜索中散列构造时冲突处理方法
- 提前退休划算不划算?你领到的钱少几十万!
- 在unity中做图片二值化的一些方法。C#
- Intellij IDEA调试功能使用总结
- Hbase-简介-结构
- AQS源码
- 2018第六届印尼(雅加达)国际安防展
- 记录no static method cannot be reference
- Stanford机器学习---第一讲. Linear Regression with one variable
- 学习日志2017.12.18
- JPA随手笔记
- 1008. 数组元素循环右移问题 (20)
- android Popupwindow被弹出软键盘挡住
- CSS-怪异盒模型和标准盒模型