ReentrantLock实现原理
ReentrantLock lock=new ReentrantLock();
lock.lock();
System.out.println("lock");
lock.unlock();
1 ReentrantLock底层是基于AQS(AbstractQueuedSynchronizer)的。
AbstractQueuedSynchronizer包含的属性包括int成员变量state表示同步状态、一个node对象(pre,next,thread,waitStatus线程状态)、两个节点(头节点,尾节点)、当前持有锁的线程。
先从公平锁开始
1 当第一个线程t1执行lock.lock()方法时:
1.1会先调用acquire方法
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
1.2 tryAcquire方法中尝试加锁
protected final boolean tryAcquire(int acquires) {
//获取当前线程
final Thread current = Thread.currentThread();
//获取同步状态
int c = getState();
//判断同步状态是否为0,此时是第一个线程没有其他线程持有锁,所以c==0
if (c == 0) {
//hasQueuedPredecessors()会判断是否需要排队,此时第一个线程是不需要排队的
//compareAndSetState时cas操作改变state的状态,
//若改变成功把当前线程设置为持有锁的线程
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
1.3上一步中的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;
//这里队列还没有被初始化,所以h==t返回false
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
!hasQueuedPredecessors()则返回true,表示不需要排队,直接cas操作改变state的状态
cas成功后tryAcquire返回true,acquire中的!tryAcquire(arg)为false,此时直接退出acquire
2 当第二个线程t2进来时,
2.1此时调用tryAcquire方法会判断state==1,
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
//第二个线程进来判断state==1
//然后判断当前线程和持有锁的线程是不是同一个(可重入)
//这里时第二个线程会直接返回false
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
tryAcquire返回false,acquire中的!tryAcquire(arg)为true,
2.2此时直接进入到acquire中acquireQueued(addWaiter(Node.EXCLUSIVE), arg)),先调用
addWaiter(Node.EXCLUSIVE)
private Node addWaiter(Node mode) {
//根据当前线程来实例化一个node
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;
//如果tail为空代表队列还没初始化
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
//此时队列还没初始化,直接进入enq方法
enq(node);
return node;
}
2.3 上一步中的enq方法
/**
这个方法执行的操作就是当队列第一次初始化时
会new一个空节点,然后把头结点指向new出来的这个空节点,尾节点指向上一步传过来的
根据当前线程来实例化的node(这里就表示为t2)。
至于为什么要new一个空节点出来,是为了表示正在持有锁的那个线程,当t2持有锁后会将t2设置为头节点,
t2的thread设置为null
*/
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
//第一次循环进来尾节点为null,cas将头指针指向new的空节点
if (compareAndSetHead(new Node()))
//然后尾指针也指向头指针
tail = head;
} else {
//第二次循环进来尾节点不为null,下面就是插入t2,将尾指针指向t2
//此时t2已经入队,不代表立即排队等待
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
2.4 addWaiter返回t2,传给acquireQueued方法
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
//当t2入队后并不会立即park,而是自旋一次,看能不能拿到锁
//会先判断自己上一个是不是head
//(若自己前面还有线程在等待,就没必要尝试拿锁了,轮不到自己)
//tryAcquire尝试获取锁,和前面一样
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
//依然拿不到锁,t2阻塞--park
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
3 当第三个线程t3来时
操作和t2一样,不同的是:
–addWaiter方法,根据当前线程来实例化一个node后,此时判断tail不为空,将node的pre指向t2,队尾指向t3,t2的next指向t3,就是把t3入队
–t3入队后就不会自旋了,因为他的上一个不是head,直接park睡眠
非公平锁情况
非公平锁会有两次抢锁过程
1 当线程进来直接cas尝试获取锁,
2 若失败会调用tryAcquire方法再次尝试加锁(判断锁的状态,若state为0直接cas获取锁,不会判断是否需要排队)
/**
和公平锁的区别在于,直接cas尝试获取锁,
*/
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
若第一次抢锁失败tryAcquire调用的是以下方法
/**
和公平锁的区别在于,若state为0直接cas获取锁,不会判断是否需要排队
*/
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;
}