2019独角兽企业重金招聘Python工程师标准>>>
只是一篇源码分析记录,写的并不详细,建议自己debug源码查看。
在计算机科学中,比较和交换(Conmpare And Swap)是用于实现多线程同步的原子指令 ,很多高性能的无锁算法就是基于这种方式实现。
//这四个参数的意思是 this对象中 的valueOffset如果是expect那么更新成update
public final native boolean compareAndSwapInt(this, valueOffset, expect, update);
在锁框架中,AbstractQueuedSynchronizer 它提供了一个基于FIFO队列(本质就是双向链表),可以用于构建锁或者其他相关同步装置的基础框架,ReentrantLook是基于它构建的。
以ReentrantLook中的公平锁为例,分析公平锁获取锁的过程。释放锁 非公平锁 先暂时不在此分析。
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
/**
* Performs {@link Lock#lock}. The main reason for subclassing
* is to allow fast path for nonfair version.
*/
abstract void lock();
//省略......
}
可以看到 ReentrantLook内部类Sync集成了抽象类AQS 。公平锁实现中 FairSync又继承了Sync
/**
* Sync object for fair locks
*/
//公平锁 代码在ReentrantLook中
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
//获取锁
acquire(1);
}
/**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
*/
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;
}
}
//代码在AbstractQueuedSynchronizer中
public final void acquire(int arg) {
//尝试获取锁 ,如果获取失败 就将当前线程放入队列中 等待唤醒
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
/**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
*/
//检测是否可以获取到锁 递归调用(也就是所说的重入锁 ),第一个 ,没有等待的 可以获取锁。
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
//获取当前锁的状态 如果为0则当前锁没有人获取
if (c == 0) {
//既然是公平锁 就要先检查队列是是否有等待的
if (!hasQueuedPredecessors() &&
//如果队列中没有等待的 那么在获取一下 成功则获取到锁 失败则可能是有人比自己抢先一部
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
//查看当前获取锁的是否就是自己 是的话则state加1
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
//代码在ReentrantLook中 既然没有获取到锁 首先将当前线程组装成链表的一个节点(队列)
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;
}
//代码在ReentrantLook中 这段代码的意思是 循环
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);
}
//代码在AbstractQueuedSynchronizer中
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
/*
* 意思是说 自己的前驱(也就是自己前面的线程)是个正常的线程 等待被唤醒
* This node has already set status asking a release
* to signal it, so it can safely park.
*/
return true;
if (ws > 0) {
/*
* 这里是说自己的前驱已经放弃治疗了 比如设置了超时机制 没有等到唤醒
* Predecessor was cancelled. Skip over predecessors and
* indicate retry.
*/
do {
那么这里在找前驱的前驱 就是找个正常的线程 毕竟要靠它来唤醒自己
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
/*
* 走到了这里说明自己的前驱很可能是0 就测试一下 如果是0就设置成-1 0是初始状态
* 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);
}
return false;
}
//代码在AbstractQueuedSynchronizer中 如果自己的前驱是正常状态 自己就可以挂起 等待自己的前驱节点唤醒
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}
这就是ReentrantLook提供的公平锁中加锁的过程。
-------------------------尽力而为------------------------------
参考:文章基于JDK8源码分析