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 }