简介
Lock接口的实现类,基本都是通过【聚合】了一个【队列同步器】的子类完成线程访问控制的。
public class ReentrantLock implements Lock, java.io.Serializable { //Lock接口的实现类
private static final long serialVersionUID = 7373984872572414699L;
/** Synchronizer providing all implementation mechanics */
private final Sync sync;
/**
* Base of synchronization control for this lock. Subclassed
* into fair and nonfair versions below. Uses AQS state to
* represent the number of holds on the lock.
* 【聚合】了一个【队列同步器】(AbstractQueuedSynchronizer)的子类(Sync)
*/
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
ReentrantLock的原理
从简单的lock方法开始看看公平和非公平
可以明显看出公平锁与非公平锁的lock()方法唯一的区别就在于公平锁在获取同步状态时多了一个限制条件:
hasQueuedPredecessors();hasQueuedPredecessors是公平锁加锁时判断等待队列中是否存在有效节点的方法。
public final boolean hasQueuedPredecessors() {
// The correctness of this depends on head being initialized
// before tail and on head.next being accurate if the current
// thread is first in queue.
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
非公平方法lock()
对比公平锁和非公平锁的tryAcquire()方法的实现代码,其实差别就在于非公平获取锁时比公平锁中少了一个判断
!hasQueuedPredecessors(); 该方法中判断了是否需要排队,导致公平锁和非公平锁的差异如下:
公平锁: 公平锁讲究先来先到,线程在获取锁时,如果这个锁的等待队列中已经有线程在等待,那么当前线程就会进入等待队列中;
非公平锁: 不管是否有等待队列,如果可以获取锁,则立刻占有锁对象。也就是说队列的第一个排队线程在unpark(),之后还是需要竞争锁(存在线程竞争的情况下)
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
整个ReentrantLock的加锁过程,可以分为三个阶段:
- 尝试加锁;
- 加锁失败,线程入队列;
- 线程入队列后,进入阻塞状态。
对应下面①②③三部分。
lock方法
acquire方法
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
/**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());//设置独占线程为当前线程
else
acquire(1);//线程B进入acquire方法
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
//acquire方法:java.util.concurrent.locks.AbstractQueuedSynchronizer#acquire
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
//继续跟踪tryAcquire方法java.util.concurrent.locks.AbstractQueuedSynchronizer#tryAcquire
//父类定义,抛出异常要求子类必须实现该方法;ctrl+alt+b找实现类
protected boolean tryAcquire(int arg) {
throw new UnsupportedOperationException();
}
//继续跟踪java.util.concurrent.locks.ReentrantLock.NonfairSync#tryAcquire
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
//继续跟踪到nonfairTryAcquire方法;如下:
目前的执行状态:
ThreadA在执行,state=1,ThreadB要进入队列排队。
tryAcquire方法
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();//获取当前线程
int c = getState();//ThreadA已经占用 1
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) { //进入else if
//current 当前线程ThreadB,getExclusiveOwnerThread()是线程ThreadA
//如果当前线程是线程拥有者,也就是true;表示是可重入锁,继续让当前线程执行
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;//返回false
}
再回到tryAcquire方法
//上面方法返回false,取反之后是true
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
如果tryAcquire(arg)返回false,取反之后返回true;则继续执行&&后面的方法 addWaiter方法。
addWaiter方法
//java.util.concurrent.locks.AbstractQueuedSynchronizer#addWaiter
private Node addWaiter(Node mode) {
//当前线程是ThreadB
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;//tail默认值是null;
if (pred != null) { //null != null false;if不执行
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);//进入该方法
return node;
}
入队方法:
/**
* Inserts node into queue, initializing if necessary. See picture above.
* @param node the node to insert
* @return node's predecessor
*/
private Node enq(final Node node) {
for (;;) { //第一次自旋 完成初始化
Node t = tail;// t = null
if (t == null) { // Must initialize 必须初始化,说明没有任何一个元素入队
if (compareAndSetHead(new Node()))//比较并设置头节点,设置新建一个空节点作为占位
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
//继续跟踪compareAndSetHead方法
/**
* CAS head field. Used only by enq.
*/
private final boolean compareAndSetHead(Node update) {
return unsafe.compareAndSwapObject(this, headOffset, null, update);
}
如图所示:
head头节点指向一个new Node() 的空接点。注意:for循环是死循环,继续执行for循环:
双向链表中,第一个节点为虚节点也叫哨兵节点,其实并不存储任何信息,只是占位。真正的第一个有数据的节点,是从第二个节点开始的。
private Node enq(final Node node) {
for (;;) { //第一次自旋完成初始化
Node t = tail;// t = null
if (t == null) { // Must initialize 必须初始化,说明没有任何一个元素入队
if (compareAndSetHead(new Node()))//比较并设置头节点,设置新建一个空节点作为占位
tail = head;
} else { //第二次自旋完成入队执行else分支
node.prev = t;//node是线程B,B节点的前指针指向尾节点
if (compareAndSetTail(t, node)) { //比较并设置尾节点为ThreadB节点
t.next = node;//哨兵节点的next指向ThreadB节点
return t;//返回t节点,头节点
}
}
}
}
第二次循环之后:
ThreadC线程执行,也是执行addWaiter方法
/**
* Creates and enqueues node for current thread and given mode.
*
* @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared
* @return the new node
*/
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred = tail; //C节点进入,
if (pred != null) { //尾指针不为null,进入if结构
node.prev = pred; //把C节点的上一个节点指向pred--->tail尾节点
if (compareAndSetTail(pred, node)) { //比较并设置尾指针为节点C
pred.next = node;//把节点C连接到尾指针
return node;
}
}
enq(node);
return node;
}
如下图所示:
小总结:
acquireQueued(addWaiter(Node.EXCULUSIVE),args)方法
继续跟踪方法:
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
这次跟踪acquireQueued方法:
/**
* Acquires in exclusive uninterruptible mode for thread already in
* queue. Used by condition wait methods as well as acquire.
*
* @param node the node
* @param arg the acquire argument
* @return {@code true} if interrupted while waiting
*/
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)) { //p == head是true,tryAcquire再次尝试失败
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
//抢占失败应该park
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed) //如果failed为true则取消入队
cancelAcquire(node);
}
}
继续跟踪shouldParkAfterFailedAcquire方法:
/**
* Checks and updates status for a node that failed to acquire.
* Returns true if thread should block. This is the main signal
* control in all acquire loops. Requires that pred == node.prev.
*
* @param pred node's predecessor holding status
* @param node the node
* @return {@code true} if thread should block
*/
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;//哨兵节点的waitStatus=0,获取前驱节点的状态
if (ws == Node.SIGNAL) // -1 不执行; 如果是SIGNAL状态,即等待被占用的资源释放,直接返回true
/*
* This node has already set status asking a release
* to signal it, so it can safely park.
*/
return true;
if (ws > 0) { //ws大于0说明是CANCELLED状态
/*
* Predecessor was cancelled. Skip over predecessors and
* indicate retry.
*/
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
/*
* waitStatus must be 0 or PROPAGATE. Indicate that we
* need a signal, but don't park yet. Caller will need to
* retry to make sure it cannot acquire before parking.
*/
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);//把哨兵节点的waitStatus由0变为-1
}
return false;
}
再跟踪acquireQueued的for循环,因为是自旋:
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)) { //p == head是true,tryAcquire再次尝试失败
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
//抢占失败应该park
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed) //如果failed为true则取消入队
cancelAcquire(node);
}
}
再次执行shouldParkAfterFailedAcquire方法:
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus; //第二次自旋 -1
if (ws == Node.SIGNAL) //true
/*
* This node has already set status asking a release
* to signal it, so it can safely park.
*/
return true; //返回true
if (ws > 0) {
....
继续跟踪acquireQueued方法:
//抢占失败应该park
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
shouldParkAfterFailedAcquire返回true之后执行&&后面的方法parkAndCheckInterrupt;
如果前驱节点的waitStatus是SIGNAL状态,即shouldParkAfterFailedAcquire方法会返回true程序会继续向下执行parkAndCheckInterrupt方法,用于将当前线程挂起。
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);//ThreadB在此一直等待,线程挂起,程序不会继续向下执行
//根据park方法api描述,程序在下述三种情况会继续向下执行
//1. 被unpark
//2. 被中断(interrupt)
//3. 其他不和逻辑的返回才会继续向下执行
//因上述三种情况程序执行至此,返回当前线程的中断状态,并清空中断状态,
//如果由于被中断,该方法会返回true
return Thread.interrupted();
}
当Node里的waitStatus等于-1时阻塞线程等待重新唤醒。也就是等待ThreadA执行unPark方法之后ThreadB才能上位执行。
小总结:执行到acquireQueued方法之后,ThreadB和ThreadC两个线程才算真正的入队完成,进入阻塞状态。
unlock方法
方法实现:
public void unlock() {
sync.release(1);
}
继续跟踪方法:
//java.util.concurrent.locks.AbstractQueuedSynchronizer#release
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
继续跟踪方法:
protected boolean tryRelease(int arg) {
throw new UnsupportedOperationException();
}
//java.util.concurrent.locks.ReentrantLock.Sync#tryRelease
protected final boolean tryRelease(int releases) {
int c = getState() - releases;//1 - 1
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) { //执行if结构
free = true;
setExclusiveOwnerThread(null);//设置当前窗口的线程为null
}
setState(c);//设置state = 0;
return free;
}
在回到release方法
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0) //h不为null, waitStatus也不为0;进入if结构
unparkSuccessor(h);//执行该方法
return true;
}
return false;
}
跟踪unparkSuccessor方法
private void unparkSuccessor(Node node) {
/*
* If status is negative (i.e., possibly needing signal) try
* to clear in anticipation of signalling. It is OK if this
* fails or if status is changed by waiting thread.
*/
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);//把waitStatus设置为0
/*
* Thread to unpark is held in successor, which is normally
* just the next node. But if cancelled or apparently null,
* traverse backwards from tail to find the actual
* non-cancelled successor.
*/
Node s = node.next;//哨兵节点的下一个节点ThreadB
if (s == null || s.waitStatus > 0) { //ThreadB的waitStatus不大于0,if块不进入
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);//解锁线程B
}
以上流程的代码:
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);//ThreadB线程出队
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) && //抢占失败后应该park
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
ThreadB线程出队过程:
private void setHead(Node node) {
head = node;
node.thread = null;
node.prev = null;
}