AQS源码分析 ---- 1

【AQS源码分析 ---- 1】文章目录
1) 同步队列
同步器依赖内部的同步队列(一个FIFO双向队列)来完成同步状态的管理,当前线程获取同步状态失败时,同步器会将当前线程以及等待状态等信息构造成为一个节点(Node)并将其加入同步队列,同时会阻塞当前线程,当同步状态释放时,会把首节点中的线程唤醒,使其再次尝试获取同步状态 。
下面直接呈上源代码!!!字多看的头疼
同步队列中的节点(Node):
static final class Node {/** waitStatus value to indicate 线程被中断或者超时 */static final int CANCELLED =1;/** waitStatus value to 按时后继节点可以运行 */static final int SIGNAL= -1;/** waitStatus value to 节点在等待队列(WAIT),等待被唤醒后加入同步队列(BLOCK) */static final int CONDITION = -2;/*** waitStatus value to indicate the next acquireShared should* unconditionally propagate*/static final int PROPAGATE = -3;// 等待状态如上所示volatile int waitStatus;// 前驱节点volatile Node prev;// 后继volatile Node next;// 获取同步状态的线程volatile Thread thread;// 等待队列中的后继节点Node nextWaiter;final boolean isShared() {return nextWaiter == SHARED;}// 获取节点的前继final Node predecessor() throws NullPointerException {Node p = prev;if (p == null)throw new NullPointerException();elsereturn p;}Node() {// Used to establish initial head or SHARED marker}Node(Thread thread, Node mode) {// Used by addWaiterthis.nextWaiter = mode;this.thread = thread;}Node(Thread thread, int waitStatus) { // Used by Conditionthis.waitStatus = waitStatus;this.thread = thread;}}
节点是构成同步队列,如下图所示 太懒直接上原图!:
注意:当线程无法获取同步状态时,需要将线程转换为Node,转存同步队列,由于加入过程需要是线程安全,所以加入CAS操作来设置尾节点,代码如下:
private Node addWaiter(Node mode) {Node node = new Node(Thread.currentThread(), mode);// tail为同步队列的尾节点Node pred = tail;if (pred != null) {node.prev = pred;// 快速尝试在尾部添加,如果CAS不存在,使用死循环的方式进行添加节点if (compareAndSetTail(pred, node)) {pred.next = node;return node;}}// 如果尾结点为nullenq(node);return node;}private Node enq(final Node node) {// “死循环”来保证节点的正确添加,for (;;) {Node t = tail;if (t == null) { // Must initializeif (compareAndSetHead(new Node()))tail = head;} else {node.prev = t;if (compareAndSetTail(t, node)) {t.next = node;return t;}}}}
过程见下图:
同步队列遵循FIFO,首节点是获取同步状态成功的节点,首节点的线程在释放同步状态时,将会唤醒后继节点,而后继节点将会在获取同步状态成功时将自己设置为首节点 。
private void unparkSuccessor(Node node) {/*获取节点状态*/int ws = node.waitStatus;// 如果小于0,为头节点状态设置初始值if (ws < 0)compareAndSetWaitStatus(node, ws, 0);/*唤醒下一个节点*/Node s = node.next;// 找到未被取消,且在同步队列中的节点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;}// 执行该线程if (s != null)LockSupport.unpark(s.thread);}
2) 独占同步状态的获取与释放调用自定义同步器实现的(int arg)方法,同步状态获取失败执行(2) 。构造同步节点(设置独占式Node.)并通过(Node node)方法将该节点加入到同步队列的尾部 。调用(Node node,int arg)方法,使得该节点以“死循环”的方式获取同步状态 。