1.5w字,30图带你彻底掌握 AQS!(建议收藏)( 四 )
几个类的关系如下:
文章插图
我们先来剖析下非公平锁(NonfairSync)的实现方式 , 来看上述示例代码的第二步:加锁 , 由于默认的是非公平锁的加锁 , 所以我们来分析下非公平锁是如何加锁的
文章插图
可以看到 lock 方法主要有两步
- 使用 CAS 来获取 state 资源 , 如果成功设置 1 , 代表 state 资源获取锁成功 , 此时记录下当前占用 state 的线程 setExclusiveOwnerThread(Thread.currentThread());
- 如果 CAS 设置 state 为 1 失败(代表获取锁失败) , 则执行 acquire(1) 方法 , 这个方法是 AQS 提供的方法 , 如下
public final void acquire(int arg) {if (!tryAcquire(arg) }
tryAcquire 剖析首先 调用 tryAcquire 尝试着获取 state , 如果成功 , 则跳过后面的步骤 。 如果失败 , 则执行 acquireQueued 将线程加入 CLH 等待队列中 。先来看下 tryAcquire 方法 , 这个方法是 AQS 提供的一个模板方法 , 最终由其 AQS 具体的实现类(Sync)实现 , 由于执行的是非公平锁逻辑 , 执行的代码如下:
final boolean nonfairTryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) {// 如果 c 等于0 , 表示此时资源是空闲的(即锁是释放的) , 再用 CAS 获取锁if (compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}else if (current == getExclusiveOwnerThread()) {// 此条件表示之前已有线程获得锁 , 且此线程再一次获得了锁 , 获取资源次数再加 1 , 这也映证了 ReentrantLock 为可重入锁int nextc = c + acquires;if (nextc < 0) // overflowthrow new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;}
此段代码可知锁的获取主要分两种情况- state 为 0 时 , 代表锁已经被释放 , 可以去获取 , 于是使用 CAS 去重新获取锁资源 , 如果获取成功 , 则代表竞争锁成功 , 使用 setExclusiveOwnerThread(current) 记录下此时占有锁的线程 , 看到这里的 CAS , 大家应该不难理解为啥当前实现是非公平锁了 , 因为队列中的线程与新线程都可以 CAS 获取锁啊 , 新来的线程不需要排队
- 如果 state 不为 0 , 代表之前已有线程占有了锁 , 如果此时的线程依然是之前占有锁的线程(current == getExclusiveOwnerThread() 为 true) , 代表此线程再一次占有了锁(可重入锁) , 此时更新 state , 记录下锁被占有的次数(锁的重入次数),这里的 setState 方法不需要使用 CAS 更新 , 因为此时的锁就是当前线程占有的 , 其他线程没有机会进入这段代码执行 。 所以此时更新 state 是线程安全的 。
文章插图
假设现在 T1 获取锁成功 , 则两种情况分别为 1、 T1 首次获取锁成功
文章插图
2、 T1 再次获取锁成功 , state 再加 1 , 表示锁被重入了两次 , 当前如果 T1一直申请占用锁成功 , state 会一直累加
文章插图
- 小米的“一连指”,能否彻底点燃UWB消费级市场?
- 微信新增6个灵魂表情,捂脸哭彻底过时,裂开表情瞬间走红
- 只需2步,彻底关闭电脑里的弹窗广告,建议收藏
- 还在为被看见聊天记录而烦恼吗?,教你彻底清空聊天记录
- 美国防部注资6亿将5G军事化,彻底颠覆战争理念
- 人工智能如何彻底改变从IVR到销售辅导的商务电话
- 国外快递成功“入侵”,半年时间就日单千万!三通一达彻底慌了
- 比特币金融:“夸克链信”彻底玩完,币价跌至3毛钱,凉凉
- iPhone12值不值得买?一张图带你看完苹果新品发布会
- 让你彻底搞懂布隆过滤器!实现一个自己的BloomFilter