独占式锁为了实现线程同步,主要是综合使用了三种手段。
- 双向链表构成的队列
- CAS原子操作
- 阻塞与释放(ParkSupport的park( )和unpark( )方法)
线程获得锁的流程如下:
- 先请求获得锁, 如果成功了就没什么说得,如果不成功则请求队列
- 请求队列的过程如图:
重要代码跟踪:
// lock方法调用 acquire 方法请求获得锁
final void lock() {
acquire(1);
}
// 这是获得锁的方法,参数arg的代表锁的类型:独占锁为1
public final void acquire(int arg) {
// 可以看出,如果不能获得锁,则请求队列。再请求队列时先生成节点
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
-----------------------------------------------------------------------------------------------
@节点的添加
// 这是生成节点的具体实现
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
Node pred = tail;
// 如果尾部节点为null,说明当前队列还没有节点
if (pred != null) {
// 设置新节点的前置节点为队列的尾部节点
node.prev = pred;
// 并做添加操作,如果成功则返回当前节点
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
// 这个方法是使用CAS的自旋确保节点成功添加,原代码见下一个方法
enq(node);
return node;
}
// 通过CAS加自旋添加节点
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;
}
}
}
}
-----------------------------------------------------------------------------------------------
// 请求队列
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);
}
}
// 阻塞的方法
private final boolean parkAndCheckInterrupt() {
// 阻塞
LockSupport.park(this);
return Thread.interrupted();
}
-----------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------
阻塞的方法什么时候被唤醒?
// 释放锁
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
// 尝试释放锁成功后,唤醒下一个被阻塞节点,代码见下一个方法
unparkSuccessor(h);
return true;
}
return false;
}
// 唤醒当前节点(参数node)的下一个节点
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)
// 如果下一个节点不为null,就唤醒。被唤醒的节点处在for循环中,继续做自己的事。新一轮请求获得锁逻辑开始。
LockSupport.unpark(s.thread);
}