提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。
提示:以下是本篇文章正文内容,下面案例可供参考
一、基于ReentrantLock的公平锁进行的解析
1、lock()
// ReentrantLock 的 lock()
public void lock() {
sync.lock();
}
// FairSync 的lock方法
final void lock() {
acquire(1);
}
// AQS 的 acquire()
/**
主流程在父类中,
部分方法留给子类自己实现,这其实就是设计模式里面的模板模式
tryAcquire 方法留给子类重写
*/
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
2、tryAcquire
尝试获取锁:
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
// AQS 的 getState() , 获取 AQS 的state
int c = getState();
if (c == 0) {
// hasQueuedPredecessors() 判断当前线程是否需要排队
// 如果不需要排队,则直接CAS尝试修改 AQS 的状态
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
// AbstractOwnableSynchronizer 的方法,设置当前线程为拥有锁的线程
setExclusiveOwnerThread(current);
return true;
}
}
// 如果state != 0 ,则需要判断当前线程是否是拥有锁的线程,如果是,则可以重入,将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;
}
3、hasQueuedPredecessors
判断是否需要排队,TODO
public final boolean hasQueuedPredecessors() {
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());
}
4、acquireQueued
阻塞等待获取锁:
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
// 获取当前节点的头节点
final Node p = node.predecessor();
// 如果前一个节点是head,则他就是排队的第一个元素。则尝试设置state
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
// 如果不是第一个排队的元素,或者获取锁失败,则进行park,即会阻塞
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
5、addWaiter
往队列中添加元素:
private Node addWaiter(Node mode) {
// 将当前线程封装成Node
Node node = new Node(Thread.currentThread(), mode);
// 取出队尾node
Node pred = tail;
/**
如果队尾不为null,则设置新的尾节点
*/
if (pred != null) { // a1
// 将当前线程的node的前一个节点设置为【原来的tail】
node.prev = pred;
if (compareAndSetTail(pred, node)) {
// 将原来的尾节点的下个节点设置为当前线程的node,可见是个双向链表
pred.next = node;
return node;
}
}
// 如果队尾为null,则说明队列没有进行初始化,进行初始化,如果不为null,也会有a1一样的操作
enq(node);
return node;
}
初始化队列:
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;
}
}
}
}
总结
参考:
参考1