AbstractQueuedSynchronizer::acquire源码笔记
此处的acquire方法指AQS内部的私有acquire方法,方法签名为
final int acquire(Node node, int arg, boolean shared, boolean interruptible, boolean timed, long time)
static final int WAITING = 1; // must be 1 static final int CANCELLED = 0x80000000; // must be negative static final int COND = 2; // in a condition wait // 此方法为私有的acquire方法,所有暴露出去的acquire方法最终都会使用不同的参数组合调用此方法 final int acquire(Node node, int arg, boolean shared, boolean interruptible, boolean timed, long time) { Thread current = Thread.currentThread(); byte spins = 0, postSpins = 0; // retries upon unpark of first thread boolean interrupted = false, first = false; Node pred = null; // predecessor of node when enqueued /* * Repeatedly: * Check if node now first * if so, ensure head stable, else ensure valid predecessor * if node is first or not yet enqueued, try acquiring * else if node not yet created, create it * else if not yet enqueued, try once to enqueue * else if woken from park, retry (up to postSpins times) * else if WAITING status not set, set and retry * else park and clear WAITING status, and check cancellation */ for (;;) { // 3个判断条件 // 1.此节点当前不是首节点 // 2.此节点前驱节点不为null // 3.此节点前驱节点不是头结点,注意头结点跟首节点不是一个概念 if (!first && (pred = (node == null) ? null : node.prev) != null && !(first = (head == pred))) { // pred.status<0 说明前驱节点已经被取消,此时做一次等待队列清理 if (pred.status < 0) { cleanQueue(); // predecessor cancelled continue; // 如果此节点的前驱节点的前驱节点为null,则直接跳到下一次循环 // Thread.onSpinWait(); 可方便虚拟机优化自选等待的过程,本身不包含额外的逻辑 } else if (pred.prev == null) { Thread.onSpinWait(); // ensure serialization continue; } } // 两个并列条件 // 1.当前节点是首节点 // 2.当前节点前驱节点未null,说明当前节点还未入队 // 只有这里的逻辑用到了tryAcquire,说明已经入队的非首节点是不能获取锁的 if (first || pred == null) { boolean acquired; // 基于是否为共享获取模式分别调用tryAcquireShared与tryAcquire // 这两个方法都是无实现方法,需要用户自己实现其语义 try { if (shared) acquired = (tryAcquireShared(arg) >= 0); else acquired = tryAcquire(arg); } catch (Throwable ex) { cancelAcquire(node, interrupted, false); throw ex; } // acquired == true 说明获取锁成功 if (acquired) { // first == true 说明当前节点为首节点 // 需要将它出队并通知后继节点,这里采用的出队方式是将前导节点删除,将此节点数据清零作为新的头结点 if (first) { node.prev = null; head = node; pred.next = null; node.waiter = null; // 如果是共享锁,通知后继节点 if (shared) signalNextIfShared(node); if (interrupted) current.interrupt(); } return 1; } } // 走到这里 node == null 说明未获取到锁并且node尚未建立(一个新线程第一次获取锁会出现这种情况) // 发现这种情况,建立新的node然后重试,新建立的node还没有入队,所以其中的数据是什么无所谓,程序因此选择建立空node if (node == null) { // allocate; retry before enqueue if (shared) node = new SharedNode(); else node = new ExclusiveNode(); // 走到这里,说明node已经建立但是并未入队,且获取锁失败 // 这种情况下,将node入队然后再次进行尝试 } else if (pred == null) { // try to enqueue node.waiter = current; Node t = tail; node.setPrevRelaxed(t); // avoid unnecessary fence if (t == null) tryInitializeHead(); else if (!casTail(t, node)) node.setPrevRelaxed(null); // back out else t.next = node; // 当前节点为首节点且自旋倒计时spin!=0 // 此时说明该节点被上一个节点唤醒成为首节点,而且自旋时间还未走完 } else if (first && spins != 0) { --spins; // reduce unfairness on rewaits Thread.onSpinWait(); // 未获取到锁,且当前node状态为0(未定义) // 此时node有两种情况,1-第一次入队获取锁失败走到这里; 2-状态为WAITING的情况下获取锁失败被park,然后被前驱节点唤醒,唤醒之后一定为首节点,其状态被复位,然后自旋时间走完来到这里 } else if (node.status == 0) { node.status = WAITING; // enable signal and recheck } else { long nanos; // (postSpins << 1) | 1 等价于 postSpins*2+1 spins = postSpins = (byte)((postSpins << 1) | 1); // 有时间限制的park和无时间限制的park if (!timed) LockSupport.park(this); else if ((nanos = time - System.nanoTime()) > 0L) LockSupport.parkNanos(this, nanos); else break; // 走到这里说明线程从park状态被唤醒 node.clearStatus(); if ((interrupted |= Thread.interrupted()) && interruptible) break; } } return cancelAcquire(node, interrupted, interruptible); }

浙公网安备 33010602011771号