linux 锁 源码,看!源码之ReentrantLock公平锁 下(内涵linux jvm实现)

本文详细解析了ReentrantLock解锁过程,包括Sync类的release方法、tryRelease方法以及unparkSuccessor方法的具体实现,帮助读者理解锁释放的内部机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本章主要讲解lock的释放,如果未了解锁获取的读者可以查看上一篇。

//属于ReentrantLock 内部实现使用的sync即FairSync类的release

//但是FairSync并没有实现release最终实现的是他的父类Sync

public void unlock() {

sync.release(1);

}

//属于Sync arg参数为1

public final boolean release(int arg) {

//调用tryRelease 返回true 说明释放成功

if (tryRelease(arg)) {

//释放成功则需要唤醒下一个Node获取锁 获取当前head

Node h = head;

//如果h等于null 说明队列未创建,还并未初始化队列

//并且当前waitStatus 不等于 0 ,因为等于零说明还未进行shouldParkAfterFailedAcquire

//则没必要唤醒 因为在park前会多次检查队列,其中shouldParkAfterFailedAcquire

//会绝对的保证head状态为-1 具体原因请查看 上篇文章

if (h != null && h.waitStatus != 0)

//如果存在唤醒Node则唤醒

unparkSuccessor(h);

return true;

}

return false;

}

//属于ReentrantLock 尝试释放当前锁

protected final boolean tryRelease(int releases) {

//当前锁的状态 默认一定是 1 而在每次重入锁的时候都会进行加1

//代表着每次获取重入锁都需要有对应的释放锁 而此处则是释放锁的 -1操作

int c = getState() - releases;

//释放锁的线程不是锁持有的线程则抛出异常

if (Thread.currentThread() != getExclusiveOwnerThread())

throw new IllegalMonitorStateException();

//释放状态默认是false失败

boolean free = false;

//如果c等于0 说明所有重入所获取的锁都进行了释放已经没有持有锁的状态

if (c == 0) {

//则释放成功并且设置锁持有对象为null

free = true;

setExclusiveOwnerThread(null);

}

//设置当前锁状态 因为释放锁的操作必须是持有锁的线程进行的

//所以此处仅仅是设置了state所以并不用cas操作因为其他线程都还卡着获取不了

//只有当前state释放了并且唤醒next才会有新的线程获取锁

//再次期间如果有新的线程进入则会加入到队列中而不是竞争锁

setState(c);

return free;

}

//属于AbstractQueuedSynchronizer

//唤醒next Node

private void unparkSuccessor(Node node) {

//获取传入node的等待状态 切记 此处Node为head 并且一定会是head

int ws = node.waitStatus;

//如果当前head的ws小于0则重置 他为1

if (ws < 0)

compareAndSetWaitStatus(node, ws, 0);

//获取node的next节点

Node s = node.next;

//如果当前节点为null 或者 ws状态大于0

if (s == null || s.waitStatus > 0) {

//不管是哪种都设置s为null 因为ws大于0 是取消状态需要跳过 null更不用说

//这两种状态都不需要唤醒所以此处跳过他设置为null

s = null;

//从尾部开始遍历 t不等于null并且不等于当前对象

for (Node t = tail; t != null && t != node; t = t.prev)

//直到获取到最后一个小于等于0的node设置为s

//因为为了保证顺序性 一定是获取的是按顺序执行的一个

//所以此处迭代不会停止会一直到结束 即t==node

if (t.waitStatus <= 0)

s = t;

}

//s == null说明没有找到需要获取锁的Node 要么队列为空 要么都取消获取锁

//相反s不等于null则唤醒s

if (s != null)

//这里需要注意的是 在获取锁的一篇中下方C代码第一段是每个Thread都有parker对象

//而此对象存储这每个Thead的锁和唤醒条件所以此处唤醒需要传入需要唤醒的线程

LockSupport.unpark(s.thread);

}

//属于LockSupport

//唤醒指定线程

public static void unpark(Thread thread) {

//线程不等于null则调用UNSAFE的unpark方法

if (thread != null)

UNSAFE.unpark(thread);

}

到此处又到了激动人心的jvm实现了。下面讲解unpark的C实现

//为了方便讲解流程将会跳过jvm的其他操作只管关键流程

//将传入的线程对象转换成 C++对象 unsafe.cpp 1300行

JavaThread thr = java_lang_Thread::thread(java_thread);

//调用thr的unpark方法 直接还有很多转换判断null之类的操作再次忽略

thr->parker()->unpark();

//其中的类在上篇已经介绍此处忽略忘记的小伙伴可以再去阅读一遍,回忆一下

//当前线程获取锁 锁的初始化在 线程创建时就初始化了而存储在Parker中

status = pthread_mutex_lock(_mutex);

//_cur_index在park时对_cond的索引做的记录所以此处可以直接唤醒

status = pthread_cond_signal (&_cond[_cur_index]);

//释放当前锁

status = pthread_mutex_unlock(_mutex);

Lock的公平锁到此基本结束,按照流程读者可以很快的了解他获取锁的流程,在简单的lock方法调用时整个系统发生的变化,从而学习设计者的设计思路。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值