标签:相同 读锁 iter com == variant bst article 它的
AbstractQueuedSynchronizer是并发编程包中最重要的类,是并发编程包的实现基层。简单来说,AbstractQueuedSynchronizer提供了一个基于FIFO的队列,用于存储处于阻塞状态的线程;提供了一个volatile修改的state变量,用于作为锁获取的标识位,对于FIFO队列和state的操作都是通过Unsafe这个类来实现CAS原子操作。
AQS的功能可以分为两类:独占功能和共享功能,它的所有子类中,要么实现了并使用了它独占锁功能的API,要么使用了共享锁的功能,而不会同时使用两套API,即便是它最有名的子类读写锁ReentrantReadWriteLock也是通过两个内部类:读锁和写锁,分别实现两套API来实现的。
//阻塞线程节点 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; //表示当前节点在等待Condition static final int PROPAGATE = -3; //表示当前场景下后续的acquireShared能够得以执行 volatile int waitStatus; volatile Node prev; volatile Node next; volatile Thread thread; Node nextWaiter; }当线程没有竞争到锁资源时就会被阻塞并放到FIFO队列中,当锁资源释放后再从FIFO由阻塞状态变为可执行状态来获取锁资源并执行。当线程获取锁资源时有公平锁和非公平锁可以参考并发编程--公平锁和非公平锁;此外对于锁的分类还有独占锁和共享锁,简单来说独占锁state就是当前锁只能有一个线程获取,其他线程处于阻塞状态,共享锁是多个线程可以同时持有当前锁状态state,只要符合某种要求所有线程可以并发执行,不用进行阻塞等待。
AQS FIFO队列模型:
AbstractQueuedSynchronizer提供了一个变量state,用来作为当前锁是否可以获取的标识,对于所有线程来说,当前state的值对于他们来说都是可见的,每个线程持有的state值都是相同的。
private volatile int state;
final void lock() { //但获取锁时,会将state设置为1,如果是单个线程多次获取锁则state++ acquire(1); }
//tryAcquire是尝试获取锁,如果获取锁则继续执行 //如果tryAcquire返回false,则调用acquireQueued将当前线程阻塞并添加的FIFO队列中 public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }我们看看tryAcquire尝试获取锁的机制,我们介绍一下公平锁的获取吧
protected final boolean tryAcquire(int acquires) { //获取当前线程 final Thread current = Thread.currentThread(); //获取锁标识state int c = getState(); //如果c等于0则表示当前线程可以获取锁 if (c == 0) { //hasQueuedPredecessors判断当前锁是否在FIFO队列中,当FIFO队列为空时,当前线程可以获取锁,不然根据公平规则,需要让FIFO中的线程优先获取锁 //当可以获取锁是调用 compareAndSetState(0, acquires)将state值通过cas操作设置为acquires if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { //将独占线程设置为当前线程 setExclusiveOwnerThread(current); return true; } } //即使当前获取不到锁,如果获取锁的线程是当前线程则state++,线程获取多个锁 else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } //获取锁失败 return false; } }总结:锁的获取是根据锁状态值state和判断当前获取锁的线程是否是申请锁的线程来判断的
private Node addWaiter(Node mode) { //创建当前线程节点Node Node node = new Node(Thread.currentThread(), mode); Node pred = tail; //当尾节点不为空时 if (pred != null) { node.prev = pred; //cas原子操作将当前线程添加到FIFO队列中 if (compareAndSetTail(pred, node)) { pred.next = node; return node; } } //当尾节点为空时,初始化head和tail节点 enq(node); //返回node return node; }接下来调用acquireQueued将线程进行阻塞
final boolean acquireQueued(final Node node, int arg) { boolean failed = true; try { boolean interrupted = false; for (;;) { //获取node节点的前一个节点 final Node p = node.predecessor(); //再尝试获取锁 if (p == head && tryAcquire(arg)) { setHead(node); p.next = null; // help GC failed = false; return interrupted; } //shouldParkAfterFailedAcquire 用来设置node的waitstatus状态为SIGNAL,值为-1,表示当前节点的后继节点包含的线程需要运行,也就是unpark; //parkAndCheckInterrupt() 操作是将当前线程park,阻塞,线程阻塞在这个地方 if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } finally { if (failed) cancelAcquire(node); } }线程阻塞的操作是在parkAndCheckInterrupt中将当前线程阻塞。
private final boolean parkAndCheckInterrupt() { //阻塞当前线程 LockSupport.park(this); return Thread.interrupted(); }总结:以上操作完成了线程的进FIFO队列及当前线程的阻塞。
public void unlock() { sync.release(1); }release中进行state恢复值并唤起阻塞线程。
public final boolean release(int arg) { //tryRelease释放锁,将state进行减值,并设置当前可执行线程为null if (tryRelease(arg)) { Node h = head; if (h != null && h.waitStatus != 0) //唤起阻塞线程 unparkSuccessor(h); return true; } return false; }tryRelease中对state进行修改,如果state的值为0的话将当前执行线程设置为null。
protected final boolean tryRelease(int releases) { //修改state值 int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { free = true; //将当前执行线程设置为空 setExclusiveOwnerThread(null); } //修改state值 setState(c); return free; }接下来的操作是调用unparkSuccessor将阻塞线程唤起
private void unparkSuccessor(Node node) { int ws = node.waitStatus; 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); }
并发编程--AbstractQueuedSynchronizer介绍和原理分析
标签:相同 读锁 iter com == variant bst article 它的
原文地址:http://blog.csdn.net/qq924862077/article/details/69469875