ReentrantLock是一个可重入锁,意思就是说可以递归的调用锁,而不会因为递归进入加锁方法而发生死锁,这里后面会添加解释
ReentrantLock是基于AQS实现,其原理和AQS大致相同,分为公平锁和非公平锁,他们都会维护一个CLH双端队列,本质上是一
个双端链表,本质上都要继承AQS并重写相应的方法 tryAcquire()方法 还有tryRelease()
final void lock() { acquire(1);}
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
尝试获取锁 acquire的意思是 尝试获取锁tryAcquire()方法如果返回true 说明获取锁成功 直接返回去执行业务代码 如果失败 看下一个方法判断acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) 包装成一个节点添加到CLH队列中
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;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
如果state是0并且CLH队列中没有节点就尝试做CAS更改state的值得操作 返回true 执行业务代码 要求提现了公平性,排队队列的特性 如果不符合 ok 看下一条
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;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);
return node;
}
包装成节点先一次尝试添加到CLH队列中去 如果不成功 操作enq()方法
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
自旋CAS并发处理的添加到CLH队列中去
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
//1
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
//2
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
添加到队列中去了 要对节点做相应的处理 会尝试唤醒节点 如果有方法调用了release方法 那么就会唤醒重新开始自旋CAS 如果是头结点的下一个节点 就可以尝试获得锁
解锁
public void unlock() {
sync.release(1);
}
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
唤醒节点 本质上是唤醒h节点的下一个节点
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;
}
只有state等于0的时候才会返回true 意味着这是可重入锁 可以多次加锁 最后也需要多次解锁 直到state等于0
private void unparkSuccessor(Node node) {
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
Node s = node.next;
if (s == null || s.waitStatus > 0) {
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);
}
解锁后一个节点 如果不成功(每一个节点都有多种状态 可能被取消)就从最后一个节点开始往前遍历做唤醒才做
LockSupport.unpark(s.thread);
唤醒后
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
//1
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
//2
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
唤醒的节点会在自旋CAS中又尝试获取锁
非公平锁不同
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
先去抢先CAS改值 体现了抢占式 非公平 不理会CLH队列情况 其他的和公平锁差不多了