Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >大厂面试必会:AQS LockSupport Unsafe之间的关系

大厂面试必会:AQS LockSupport Unsafe之间的关系

作者头像
hugo_lei
发布于 2021-08-16 10:14:57
发布于 2021-08-16 10:14:57
62800
代码可运行
举报
运行总次数:0
代码可运行

文章目录

概述

AQS 是实现各种业务 Lock 的基础框架,例如ReentrantLock的实现底层就是使用 AQS。我们可以参考ReentrantLock来实现自己特定需求的 Lock 逻辑。

AQS 框架本身依赖两个强有力的工具,Unsafe 和 LockSupport,可以说是左膀右臂。

因此理解 AQS 中是如何使用 Unsafe 和 LockSupport 的,有助于我们理解各类 Lock 的底层实现原理,也可以在面试时系统地回答 AQS 相关的问题。

AQS与Unsafe

AQS 中对 Unsafe 的使用,主要是 CAS 操作。 例如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
* CAS head field. Used only by enq.
* 入队时 CAS 修改队列 head
*/
private final boolean compareAndSetHead(Node update) {
	return unsafe.compareAndSwapObject(this, headOffset, null, update);
}

/**
* CAS tail field. Used only by enq.
* 入队时 CAS 修改队列 tail
*/
private final boolean compareAndSetTail(Node expect, Node update) {
	return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
}

AQS 与 LockSupport

AQS 里对 LockSupport 的使用,主要是用于将入队后的线程 park,以及unpark 队列中某个线程。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 未获取到锁的线程被包装成 Node,然后加入队列中
// 进入队列的 Node 如果处在 head,则尝试抢锁一次
// 若不在 head 位置或在 head 抢锁不成功,则进入 park
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)) { // 前一个节点是head,则尝试抢锁一次
				setHead(node); // 抢锁成功,自己变为 head
				p.next = null; // help GC
				failed = false;
				return interrupted;
			}
			if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) // 若 Lock 的逻辑是抢锁失败后 park,则这里让线程进入 park
				interrupted = true;
		}
	} finally {
		if (failed)
			cancelAcquire(node);
	}
}

// 入队的线程 park
private final boolean parkAndCheckInterrupt() {
	LockSupport.park(this);
	return Thread.interrupted();
}

LockSupport 与 Unsafe

LockSupport的两个核心方法park()和unpark(Thread thread),内部都是通过 Unsafe 的方法来实现。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// LockSupport 的 park 方法直接调用 Unsafe#park
public static void park() {
	UNSAFE.park(false, 0L);
}
// LockSupport 的 unpark 方法直接调用 Unsafe#unpark
public static void unpark(Thread thread) {
	if (thread != null)
		UNSAFE.unpark(thread);
}

Unsafe park unpark 原理

Linux系统下,是用的Posix线程库pthread中的mutex(互斥量),condition(条件变量)来实现的。且在 park unpark 过程中,保护了一个_counter的变量。

当调用park时,先尝试能否直接拿到“许可”,即判断_counter>0时,如果成功,则把_counter设置为0,并返回。否则进入等待。

当调用 unpark 时,直接设置_counter为1,再unlock mutex返回。如果_counter之前的值是0,则还要调用pthread_cond_signal唤醒在park中等待的线程。

源码讲解可参考LockSupport(park/unpark)源码分析

LockSupport 与 wait notify 的区别

  1. wait notify 必须在 synchronized 获取锁后调用
  2. notify notifyAll 无法精确唤醒某一个线程,unpark(Thread)可以做到
  3. LockSupport#unpark(Thread)可以先于该 Thread park()前执行,这种情况下该 Thread park()时立即返回(因为底层_counter>0)

【参考】

  1. https://www.jianshu.com/p/e3afe8ab8364
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/04/28 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
并发编程基础ReentrantLock源码分析
Note1:(双向链表。初始的时候head和tail都指向Null,之后添加新节点的时候会创建一个空Node,head和tail都指向这个空Node代表初始化完成。
北洋
2022/03/09
1980
AbstractQueuedSynchronizer原理剖析
无论是公平锁还是非公平锁,它们的实现都依赖于AbstractQueuedSynchronizer,它提供了一个基于先进先出等待队列 实现block locks和synchronizers的框架。特性如下
爬蜥
2019/07/09
3200
【深入AQS原理】我画了35张图就是为了让你深入 AQS
谈到并发,我们不得不说AQS(AbstractQueuedSynchronizer),所谓的AQS即是抽象的队列式的同步器,内部定义了很多锁相关的方法,我们熟知的ReentrantLock、ReentrantReadWriteLock、CountDownLatch、Semaphore等都是基于AQS来实现的。
一枝花算不算浪漫
2020/05/07
2.3K1
【深入AQS原理】我画了35张图就是为了让你深入 AQS
JUC包深度讲解AQS(AbstractQueuedSynchronizer)源码
AQS(AbstractQueuedSynchronizer),抽象队列同步器是用来构建锁或者其他同步器组件的重量级基础框架及整个JUC体系的基石,内置FIFO队列来完成资源获取线程的排队工作,并通过一个int类型变量(state)表示持有锁的状态Reentrantlock、CountDownLatch、等juc锁和工具类.
小明爱吃火锅
2023/12/06
2621
如何手写一个AQS?
AQS即AbstractQueuedSynchronizer,是用来实现锁和线程同步的一个工具类。大部分操作基于CAS和FIFO队列来实现。
Java识堂
2021/03/30
4560
如何手写一个AQS?
AQS源码分析看这一篇就够了
好了,我们来开始今天的内容,首先我们来看下AQS是什么,全称是 AbstractQueuedSynchronizer 翻译过来就是【抽象队列同步】对吧。通过名字我们也能看出这是个抽象类
用户4919348
2020/06/02
1.1K0
Juc并发编程06——深入剖析队列同步器AQS源码
原来lock,unlock等核心方法都是通过sync来实现的。而sync其实是它的一个内部类。
半旧518
2022/10/26
2710
Juc并发编程06——深入剖析队列同步器AQS源码
话说AQS
AQS 如果没有具体的实现类,DEMO是没有意义的 , 我们先简单看一下里边常用的一些方法吧
木子的昼夜
2021/03/09
2800
话说AQS
【腾讯阿里最全面试题】介绍下Synchronized、Volatile、CAS、AQS,以及各自的使用场景
谈到并发,不得不谈ReentrantLock;而谈ReentrantLock,不得不谈AbstractQueuedSynchronizer(AQS)!
一个会写诗的程序员
2020/12/21
1.4K0
【腾讯阿里最全面试题】介绍下Synchronized、Volatile、CAS、AQS,以及各自的使用场景
JAVA面试备战(十五)--AQS独占锁获取
AQS(AbstractQueuedSynchronizer)是JAVA中众多锁以及并发工具的基础,其底层采用乐观锁,大量使用了CAS操作, 并且在冲突时,采用自旋方式重试,以实现轻量级和高效地获取锁。
程序员爱酸奶
2022/04/12
5010
JAVA面试备战(十五)--AQS独占锁获取
ReentrantLock加锁与释放过程
对于公平锁(FairSync)而言在加锁的过程中会有所不同 , 仅仅只是在申请锁的时候 , 加入了队列的判断 , 如果头节点有后继节点的话 , 则让后继节点获取CPU
None_Ling
2020/09/02
1K0
AQS
AQS全称是AbstractQueuedSynchronizer,形如其名,抽象队列同步器。
在下是首席架构师
2022/08/01
3150
Java并发编程实战: AQS 源码 史上最详尽图解+逐行注释
一般是一个state属性,它基本是整个工具的核心,通常整个工具都是在设置和修改状态,很多方法的操作都依赖于当前状态是什么。
一个会写诗的程序员
2019/07/15
1.5K0
Java并发编程实战: AQS 源码 史上最详尽图解+逐行注释
Java并发之Condition--生产者、消费者案例以及部分源码解读
Condition 是一个接口。 Condition 接口的实现类是AQS中的内部类:java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject。 Lock接口中有一个java.util.concurrent.locks.Lock.newCondition方法获取Condition。 常用的实现有重入锁的实现:
青山师
2023/05/05
2450
Java并发之Condition--生产者、消费者案例以及部分源码解读
从源码角度彻底理解ReentrantLock(重入锁)
在 ReentrantLock(重入锁)功能详解和应用演示这篇文章里我们讲解并演示了ReentrantLock(重入锁)的各种功能,其中就谈到ReentrantLock可以有公平锁和非公平锁的不同实现,只要在构造它的时候传入不同的布尔值,继续跟进下源码我们就能发现,关键在于实例化内部变量 sync的方式不同,如下所示
全栈程序员站长
2022/09/19
5910
从源码角度彻底理解ReentrantLock(重入锁)
JUC并发—5.AQS源码分析一
ReentractLock是重入锁,属于排他锁,功能和synchronized类似。但是在实际中,其实比较少会使用ReentrantLock。因为ReentrantLock的实现及性能和syncrhonized差不多,所以一般推荐使用synchronized而不是ReentrantLock。
东阳马生架构
2025/04/24
990
【92期】面试官:你说你精通Java并发,那给我讲讲J.U.C吧
来自:https://www.zybuluo.com/adamhand/note/1313016
良月柒
2020/11/23
3860
【92期】面试官:你说你精通Java并发,那给我讲讲J.U.C吧
【Java并发系列】AQS原理
Java供用户直接使用的锁有"synchronized同步锁"和"JUC包中的锁"。
章鱼carl
2022/03/31
3830
【Java并发系列】AQS原理
AQS (Abstract Queued Synchronizer)源码解析 -- 独占锁与共享锁的加锁与解锁
AQS (Abstract Queued Synchronizer) 是 JDK 提供的一套基于 FIFO 同步队列的阻塞锁和相关同步器的一个同步框架,通过 AQS 我们可以很容易地实现我们自己需要的独占锁或共享锁。 java 中,我们曾经介绍过的信号量、ReentrantLock、CountDownLatch 等工具都是通过 AQS 来实现的。
用户3147702
2022/06/27
8800
AQS (Abstract Queued Synchronizer)源码解析 -- 独占锁与共享锁的加锁与解锁
【洞悉AQS】通过ReentrantLock一步一图彻底了解AQS实现原理
谈到并发,我们不得不说AQS(AbstractQueuedSynchronizer),所谓的AQS即是抽象的队列式的同步器,内部定义了很多锁相关的方法,例如:
一枝花算不算浪漫
2022/05/11
3180
【洞悉AQS】通过ReentrantLock一步一图彻底了解AQS实现原理
推荐阅读
相关推荐
并发编程基础ReentrantLock源码分析
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验