java AQS源码分析

java常用的锁ReentrantLock主要利用AQS框架实现,ReentrantLock主要结构如图

其主要利用的是内部类Sync来实现加锁解锁操作,而Sync继承了AbstractQueuedSynchronizer累,大部分操作由AbstractQueuedSynchronizer来完成

ReentrantLock常用方法为加锁lock()与解锁unlock(), 加锁利用了AbstractQueuedSynchronizer的acquire方法,AbstractQueuedSynchronizer本身没有实现tryAcquire方法,并且抛出一个异常强制子类必须实现才能成为一个锁类,ReentrantLock通过内部类NonfairSync与FairSync提供了两个不同的tryAcquire实现来构造公平锁或者与公平锁,下面先介绍公平锁的原理

 1 protected boolean tryAcquire(int acquires) {
 2             final Thread current = Thread.currentThread();
 3             int c = getState();
 4             if (c == 0) {
 5                 if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) {
 6                     setExclusiveOwnerThread(current);
 7                     return true;
 8                 }
 9             } else if (current == getExclusiveOwnerThread()) {
10                 int nextc = c + acquires;
11                 if (nextc < 0)
12                     throw new Error("Maximum lock count exceeded");
13                 setState(nextc);
14                 return true;
15             }
16             return false;
17         }

 

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

 

 

该方法先调用tryAcquire来快速尝试获取锁,若失败则先调用addWaiter方法来构造一个同步节点,通过死循环+cas方式将此节点加到同步队列尾部,然后调用 acquireQueued来循环获取同步状态,获取到了才推出,因为只要当前节点是头节点时才能拿到状态,所以该过程类似于接力棒,从头结点开始往后一个个获取到同步状态

 1 private Node addWaiter(Node mode) {
 2         Node node = new Node(Thread.currentThread(), mode);
 3         // Try the fast path of enq; backup to full enq on failure
 4         Node pred = tail;
 5         if (pred != null) {
 6             node.prev = pred;
 7             if (compareAndSetTail(pred, node)) {
 8                 pred.next = node;
 9                 return node;
10             }
11         }
12         enq(node);
13         return node;
14     }
15 private Node enq(final Node node) {
16         for (;;) {
17             Node t = tail;
18             if (t == null) { // Must initialize
19                 if (compareAndSetHead(new Node()))
20                     tail = head;
21             } else {
22                 node.prev = t;
23                 if (compareAndSetTail(t, node)) {
24                     t.next = node;
25                     return t;
26                 }
27             }
28         }
29     }

 

 1 final boolean acquireQueued(final Node node, int arg) {
 2         boolean failed = true;
 3         try {
 4             boolean interrupted = false;
 5             for (;;) {
 6                 final Node p = node.predecessor();
 7                 if (p == head && tryAcquire(arg)) {
 8                     setHead(node);
 9                     p.next = null; // help GC
10                     failed = false;
11                     return interrupted;
12                 }
13                 if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())
14                     interrupted = true;
15             }
16         } finally {
17             if (failed)
18                 cancelAcquire(node);
19         }
20     }

 

获取同步状态的节点释放是调用release方法,由此实现了加锁解锁操作,并且按照线程请求顺序依次进行

1 public final boolean release(int arg) {
2         if (tryRelease(arg)) {
3             Node h = head;
4             if (h != null && h.waitStatus != 0)
5                 unparkSuccessor(h);//该节点释放同步状态,并唤醒下一个节点
6             return true;
7         }
8         return false;
9     }

 

posted @ 2019-07-30 18:25  高少振  阅读(295)  评论(0编辑  收藏  举报