1.继承图
Lock接口负责给各种锁提供需要实现的方法模板
Sync是ReentrantLock的内部类,继承自AQS
AQS继承自AOS
2.非公平锁的加锁流程
构造方法 (ReentrantLock类中)
public ReentrantLock() { sync = new NonfairSync(); }
加锁方法 (ReentrantLock类中)
public void lock() { sync.lock(); }
NonfairSync的lock() (ReentrantLock类中)
final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); }
加锁成功
使用cas把state的值从0修改为1,说明加锁成功,调用AOS的方法把当前线程设置为独占线程。
加锁失败
使用cas修改state的值失败,说明加锁失败,调用AQS中的acquire()方法。
acquire(1) (AQS类)
public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }
① tryAcquire(1):该方法作用是加锁失败后再尝试加一次锁
AQS中只是提供了tryAcquire方法的模板,在NonfairSync类中重写该方法
protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); }
final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; }
②tryAcquire(1)方法仍然加锁失败的话,调用acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) 将该线程加入等待队列。
private Node addWaiter(Node node) { Node node = new Node(Thread.currentThread(), mode); // Try the fast path of enq; backup to full enq on failure Node pred = tail; if (pred != null) { node.prev = pred; if (compareAndSetTail(pred, node)) { pred.next = node; return node; } } enq(node); return node; }
final boolean acquireQueued(final Node node, int arg) { boolean failed = true; try { boolean interrupted = false; for (;;) { final Node p = node.predecessor(); if (p == head && tryAcquire(arg)) { setHead(node); p.next = null; // help GC failed = false; return interrupted; } if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } finally { if (failed) cancelAcquire(node); } }
addWaiter方法是将Node节点互相连接起来形成一个双向链表
acquireQueued()是将节点加入进等待队列
大体流程如下:
假如该节点是第一个进入队列的,会先自动创建一个值为空的节点dummy,让head指向dummy,然后将第一个节点挂载到dummy后面,并将dummy的waitState值设置为-1,并将tail指向第一个节点。
如果该节点入队时不是第一个节点,则挂载到tail指向的节点之后,并将tail指向新加入的节点。
如果当前节点是第一个有效节点(前一个节点是dummy),则调用acquireQueued()时,会再尝试两次加锁,失败则会用LockSupport.park()进入阻塞,如果当前节点不是第一个有效节点,那么直接进入阻塞。
当前持有锁的线程unLock()以后,会唤醒阻塞的线程节点,依次出队使用锁。
3.非公平锁的含义
非公平锁是指,如果当前占有锁的线程释放锁以后,阻塞队列的第一个有效节点和在此刻新启动的线程同时抢占锁,如果新启动的线程抢占成功,则阻塞队列的第一个有效节点继续阻塞。
4.解锁流程
unlock() (ReentrantLock类中)
public void unlock() { sync.release(1); }
AQS的release方法 (AQS类中)
public final boolean release(int arg) { if (tryRelease(arg)) { Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h); return true; } return false; }
tryRelease()方法由NonfairSync和fairSync实现,但这两个同步器类公用一个方法
(ReentrantLock类中)
protected final boolean tryRelease(int releases) { int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { free = true; setExclusiveOwnerThread(null); } setState(c); return free; }
release()方法释放锁后,会unpark()阻塞队列的第一个有效节点Node,Node中存储的成员变量为Thread,试图抢占锁,抢占成功的话,第一个有效节点变为dummy,最初的dummy断开连接被回收,第一个有效节点的值设置为null,waitState设置为0。