Java-并发高频面试题-2
接着之前的Java-并发高频面试题
7. synchronized的实现原理是怎么样的?
首先我们要知道synchronized它是解决线程安全问题的一种方式,而具体是怎么解决的呢?主要是通过加锁的方式来解决
在底层实现上来看 是通过 monitorenter、monitorexit两个指令来实现同步,monitorenter 指令指向同步代码块的开始位置, monitorexit 指令则指向同步代码块的结束位置。
那么synchronized是如何保证原子性的呢?
synchronized保证原子性主要就是通过上面说的monitorenter、monitorexit两个指令,当执行到monitoreter的时候要先获得锁,而执行monitorexit的时候则要释放锁,
这样一来通过两个指令就可以保证被synchronized修饰的代码同一时间只能被一个线程访问,在锁未释放之前,无法被其他线程访问到。所以说synchronized是可以保证原子性的
那么synchronized是如何保证可见性的呢?
- 线程加锁前,将清空工作内存中共享变量的值,从而使用共享变量时需要从主内存中重新读取最新的值。
- 线程加锁后,其它线程无法获取主内存中的共享变量。
- 线程解锁前,必须把共享变量的最新值刷新到主内存中。
简单说来就是被synchronized修饰的代码,为了保证可见性,它在对变量解锁之前,会强制将变量的值同步回主内存中,这样在解锁之后,其他线程也就可以访问到被修改后的值;
那么synchronized是如何保证有序性的呢?
首先我们要知道有序性的定义就是按照代码的先后顺序来去执行,那么synchronized基于monitorenter 和monitorexit加锁后本身就是会单个线程来去运行,而按照as-if-sieal语义来看,编译器和执行器即便在进行指令重排 也必须要保证单线程的执行结果不能改变
所以总结一下:因为被synchronized修饰的代码,同一个时间只能被一个线程访问,也就是单线程执行的,所以是天然可以保证有序性的
8. 锁升级?synchronized锁优化介绍下?
如果要想清楚锁升级,需要先知道不同锁的状态,这个锁状态其实就是java对象头中的mark word 标记字段,而这块结构会随着锁的状态的变化而变化。
如下图所示:
再具体细看 Mark Word存储的是对象自身的 运行数据,如哈希码、GC分代年龄、锁状态标志、偏向时间戳(Epoch) 等信息。
而从上图也可以看出因为mark word状态的不同又可以区分出无锁,偏向锁,轻量级锁,重量级锁,我们依次介绍下吧
无锁:简单来说就是mark word中锁状态为01时,同时在低三位不是偏向锁的状态
偏向锁:就是mark word 中锁状态为01 同时低三位是偏向锁状态
轻量级锁:mark word中锁状态为00标志
重量级锁:mark word中锁状态为10标志
那么他们之间是怎么转化升级的呢?
锁升级方向:无锁–>偏向锁—> 轻量级锁---->重量级锁,这个方向基本上是不可逆的。
首先呢其实是无锁状态 也就是不加锁;
之后当一个线程第一次访问对象时,jvm它其实会在对象头中设置该线程的thread ID,然后将对象的状态位设置为偏向锁,设置成偏向锁以后,如果有其他线程来访问该对象,那么就会检查该对象的偏向锁状态标志,如果说和自己的线程ID相同那么就会直接获取到锁,而如果不同,那么偏向锁就会升级为轻量级锁状态,而轻量级锁下,jvm会将mark word复制一份到线程栈中,并在对象头中存储线程栈的指针。
然后如果有其他线程来访问该对象时,会发现该对象已经处于轻量级锁状态,那么就会尝试用cas操作将对象头中的指针替换成自己的指针。如果能够替换成功,也就会获取到锁;如果替换失败,表示已经有其他线程获取了锁,那么这个轻量级锁就会升级为重量级锁。
如果锁一旦升级为重量级锁,其实也就是最笨重原始的加锁,会基于objectMonitor中的等待队列排队加锁,并会在对象头中记录指向等待队列的指针,也就是说在这种情况下 如果一个线程想要加锁,就需要先进入等待队列,等待锁被释放,当锁被释放以后,jvm会从等待队列中选择一个线程来唤醒,然后线程会进入就绪状态,等待重新获取对象的锁
9.synchronized和ReentrantLock的区别有哪些?
其实大致可以从锁的实现,使用,性能,功能特点来展开去描述
锁的实现:synchronized是关键字,是基于JVM来去实现的,而ReentrantLock是类,是基于java api来去实现的
锁的使用:synchronized作为关键字 是可以修饰方法和同步代码块,会自动释放锁,而ReentrantLock 作为类是通过lock、unlock方法来完成加锁和解锁,需要手动释放锁。
性能:synchronized在早期版本中性能不如ReentrantLock,但是在1.6后增加了适应性自旋、锁消除等,两者性能就差不多了
功能特点:Reentrantlock支持公平锁和非公平锁,但是synchronized是非公平锁,(即线程是否要排队加锁)
synchronized与wait()和notify()/notifyAll()方法结合实现等待/通知机制,ReentrantLock类借助Condition接口与newCondition()方法实现。
ReentrantLock提供了能够中断等待锁的线程机制,即通过lock.lockInterruptibly()来实现该机制
10.什么是AQS?
简单来说AQS 就是抽象队列同步器,是java并发编程底层的核心实现类,
AQS 的核心思想是利用一个双向队列来保存等待锁的线程,同时利用一个 state 变量来表示锁的状态。AQS 的同步器可以分为独占模式和共享模式两种。
独占模式是指同一时刻只允许一个线程获取锁,常见的实现类有 ReentrantLock;
共享模式是指同一时刻允许多个线程同时获取锁,常见的实现类有 Semaphore、CountDownLatch、CyclicBarrier 等。
我们首先看下独占模式的原理
简单说就是独占模式下AQS 维护了一个同步队列,和一个state变量,队列中会保存了所有等待获取锁的线程。如果有多个线程同时再执行加锁操作时,会通过cas操作才更新AQS内部的state的值,如果某一个线程加锁成功会将state的值更改为1,同时aqs中会指定加锁线程为当前线程,与此同时别的线程加锁失败会进入等待队列
一旦加锁线程释放锁就会将state的值设为0,同时将加锁线程更新为null,而加锁线程也会通知排在等待队列中的头元素
同时 独占模式又分为公平锁和非公平锁:默认非公平锁
公平锁:按照线程在队列中的排队顺序,先到者先拿到锁;
非公平锁:当线程要获取锁时,无视队列顺序直接去抢锁,谁抢到就是谁的。
共享模式的原理
AQS 维护了一个等待队列和一个共享计数器。共享计数器表示当前允许获取锁的线程数,当一个线程尝试获取锁时,如果当前允许获取锁的线程数已经达到了最大值,则将该线程加入到等待队列中,并挂起线程,等待其他线程释放锁或者共享计数器增加。
当锁被释放时,会从等待队列中取出一个线程,使其获取锁,同时将它从队列中移除,唤醒该线程继续执行。
11 保证线程安全的手段有哪些?
在 Java 中,多线程并发操作同一个共享变量时,就可能会发生线程安全问题。
在 Java 中保证线程安全的常用手段有以下三个:
锁机制:在 Java 中,锁机制主要有两种:synchronized 关键字和 Lock 接口。synchronized 关键字是 Java 中最基本的锁机制,它可以用来修饰方法或代码块,以实现对共享资源的互斥访问。而 Lock 接口是 Java5 中新增的一种锁机制,它提供了比 synchronized 更强大、更灵活的锁定机制,例如可重入锁、读写锁等;
使用线程安全的容器:如 **ConcurrentHashMap、Hashtable、Vector。**需要注意的是,线程安全的容器底层通常也是使用锁机制实现的;
使用本地变量ThreadLocal:线程本地变量是一种特殊的变量,它只能被同一个线程访问。在 Java 中,线程本地变量可以通过 ThreadLocal 类来实现。每个 ThreadLocal 对象都可以存储一个线程本地变量,而且每个线程都有自己的一份线程本地变量副本,因此不同的线程之间互不干扰。
12 ThreadLocal是什么?
ThreadLocal,也就是线程本地变量。如果你创建了一个ThreadLocal变量,那么访问这个变量的每个线程都会有这个变量的一个本地拷贝,多个线程操作这个变量的时候,实际是操作自己本地内存里面的变量,从而起到线程隔离的作用,避免了线程安全问题。
而ThreadLocal用起来并不麻烦,就是声明该变量,然后通过set 写入和get获取就可以进行操作
那你在工作中有用到ThreadLocal吗?
threadLocal的场景很多 比如说可以基于threadlocal做用户信息的上下文存储,以及cookie,session等的隔离,还有比如数据库连接池 可以交给ThreadLoca进行管理,保证当前线程的操作都是同一个Connnection
ThreadLocal怎么实现的呢?实现原理是啥?
其实TheadLocal本身并不存储数据,真正存储数据的是Threadlocalmap,
也就是说每个线程都会有一个属于自己的ThreadLocalMap,
而ThreadLocalMap内部维护着Entry数组,每个Entry代表一个完整的对象,key是ThreadLocal的弱引用,value是ThreadLocal的泛型值。
每个线程在往ThreadLocal里设置值的时候,都是往自己的ThreadLocalMap里存,读也是以某个ThreadLocal作为引用,在自己的map里找对应的key,从而实现了线程隔离。
ThreadLocal 内存泄露是怎么回事?
因为 ThreadLocalMap中使用的 key 为 ThreadLocal 的弱引用。
而“弱引用的定义是 只要垃圾回收机制一运行,不管JVM的内存空间是否充足,都会回收该对象占用的内存。”
所以说 弱引用很容易被回收,如果ThreadLocal(ThreadLocalMap的Key)被垃圾回收器回收了,但是ThreadLocalMap生命周期和Thread是一样的,它这时候如果不被回收,就会出现这种情况:ThreadLocalMap的key没了,value还在,这就会造成了内存泄漏问题。
那怎么解决内存泄漏问题呢?
其实 很简单,使用完ThreadLocal后,及时调用remove()方法释放内存空间。
那为什么key还要设计成弱引用?
key设计成弱引用同样是为了防止内存泄漏。
假如key被设计成强引用,如果ThreadLocal 的引用即指针被销毁,此时它指向ThreadLoca的强引用就没有了,但是此时key还强引用指向ThreadLocal,就会导致ThreadLocal不能被回收,这时候就发生了内存泄漏的问题。
13 线程死锁的条件有哪些?
死锁的产生需要满足以下 4 个条件:
互斥条件:也就是说在一段时间内某个锁资源只能被一个运算单元所占用。
请求和保持条件:说白了就是当前线程A占用着某个资源a,但是又去请求其他资源b,而资源b又恰好被其他线程B占用着不释放,就是处于这种请求保持条件
不可剥夺条件:指运算单元已获得的资源,在未使用完之前,不能被剥夺。
环路等待条件:指在发生死锁时,必然存在运算单元和资源的环形链,即运算单元正在等待另一个运算单元占用的资源,而对方又在等待自己占用的资源,从而造成环路等待的情况。
只有以上 4 个条件同时满足,才会造成死锁。
死锁的常用解决方案有以下两个:
按照顺序加锁:尝试让所有线程按照同一顺序获取锁,从而避免死锁。
设置获取锁的超时时间:尝试获取锁的线程在规定时间内没有获取到锁,就放弃获取锁,避免因为长时间等待锁而引起的死锁。
死锁排查工具有哪些?
常见的工具有以下几个:
jstack:可以查看 Java 应用程序的线程状态和调用堆栈,可用于发现死锁线程的状态。
jconsole 和 JVisualVM:这些是 Java 自带的监视工具,可以用于监视线程、内存、CPU 使用率等信息,从而帮助排查死锁问题。
14 CAS了解吗?有哪些实现?以及存在哪些问题?
CAS叫做CompareAndSwap,⽐较并交换,主要是通过处理器的指令来保证操作的原⼦性的。
CAS 指令包含 3 个参数:共享变量的内存地址 A、预期的值 B 和共享变量的新值 C。
只有当内存中地址 A 的值等于 B 时,才能将内存中地址 A 的值更新为新值 C。作为一条 CPU 指令,CAS 指令本身是能够保证原子性的
具体实现:在 Java 中,CAS 操作被封装在 Atomic 类中,例如 AtomicInteger 类就是利用了 CAS 操作来实现线程安全的自增操作。同时,Java 还提供了一些工具类来支持 CAS 操作,例如 Unsafe 类,它提供了一些原始的 CAS 操作方法,供 JVM 内部使用
CAS存在的问题
1. ABA问题
并发环境下,假设初始条件是A,去修改数据时,发现是A就会执行修改。但是看到的虽然是A,中间可能发生了A变B,B又变回A的情况
那该如何解决ABA问题呢?
加版本号或者时间戳,说白了就是每次修改变量,都在这个变量的版本号上加1,这样,刚刚A->B->A,虽然A的值没变,但是它的版本号已经变了,再判断版本号就会发现此时的A已经被改过了。参考乐观锁的版本号,这种做法可以给数据带上了一种实效性的检验。
Java提供了AtomicStampReference类,它的compareAndSet方法首先检查当前的对象引用值是否等于预期引用,并且当前印戳(Stamp)标志是否等于预期标志,如果全部相等,则以原子方式将引用值和印戳标志的值更新为给定的更新值。
2. 只能保证一个变量的原子操作
CAS 保证的是对一个变量执行操作的原子性,如果对多个变量操作时,CAS 目前无法直接保证操作的原子性的。
怎么解决只能保证一个变量的原子操作问题?
可以考虑改用锁来保证操作的原子性
可以考虑合并多个变量,将多个变量封装成一个对象,java中可以用AtomicReference来保证原子性
3. 无限循环导致性能降低
自旋CAS,如果一直循环执行,一直不成功,会给CPU带来非常大的执行开销。
那么如何来解决循环问题呢?可以通过设置自旋次数,即超过一定次数,就停止自旋
15. AtomicInteger 的原理?
说白了 就是基于CAS来实现的,在底层是用Unsafe类的实例来进行添加操作,而Unsafe类中的compareAndSwapInt其实就是一个native方法,基于CAS来操作int类型变量。
public final int getAndAddInt(Object var1, long var2, int var4) {int var5;do {var5 = this.getIntVolatile(var1, var2);} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));return var5;
}
相关文章:

Java-并发高频面试题-2
接着之前的Java-并发高频面试题 7. synchronized的实现原理是怎么样的? 首先我们要知道synchronized它是解决线程安全问题的一种方式,而具体是怎么解决的呢?主要是通过加锁的方式来解决 在底层实现上来看 是通过 monitorenter、monitorexit…...
Windows安装Redis
安装Redis是一个比较简单的过程,以下是在Windows上安装Redis的基本步骤: 下载Redis:首先,你需要从Redis官方网站(https://redis.io/download)下载适合Windows的Redis安装包。你可以选择稳定版本或者开发版本…...

Nicn的刷题日常之 有序序列判断
目录 1.题目描述 描述 输入描述: 输出描述: 示例1 示例2 示例3 2.解题 1.题目描述 描述 输入一个整数序列,判断是否是有序序列,有序,指序列中的整数从小到大排序或者从大到小排序(相同元素也视为有序)。 数据…...

1、将 ChatGPT 集成到数据科学工作流程中:提示和最佳实践
将 ChatGPT 集成到数据科学工作流程中:提示和最佳实践 希望将 ChatGPT 集成到您的数据科学工作流程中吗?这是一个利用 ChatGPT 进行数据科学的提示的实践。 ChatGPT、其继任者 GPT-4 及其开源替代品非常成功。开发人员和数据科学家都希望提高工作效率,并使用 ChatGPT 来简…...

vite+vue3发布自己的npm组件+工具函数
记录一下个人最近一次发布npm组件的过程: 一、创建组件和工具函数 执行命令创建一个空项目: npm create vite 创建过程稍微有些慢,不知何故?其中选择vue , 个人暂时使用的JS 。在 src 目录下面创建一个文件 package 存放组件和公…...

嵌入式软件bug分析基本要求
摘要:软件从来不是一次就能完美的,需要以包容的眼光看待它的残缺。那问题究竟为何产生,如何去除呢? 1、软件问题从哪来 软件缺陷问题千千万万,主要是需求、实现、和运行环境三方面。 1.1 需求描述偏差 客户角度的描…...

【C/C++ 17】继承
目录 一、继承的概念 二、基类和派生类对象赋值转换 三、继承的作用域 四、派生类的默认成员函数 五、继承与友元 六、继承与静态成员变量 七、菱形继承与虚拟继承 一、继承的概念 继承是指一个类可以通过继承获得另一个类的属性和方法,扩展自己的功能&…...
解决Linux Shell脚本错误:“/bin/bash^M: bad interpreter: No such file or directory”
在Linux系统中运行Shell脚本时,你可能会遇到一个常见的错误,错误信息如下: -bash: ./xxx.sh: /bin/bash^M: bad interpreter: No such file or directory这个错误通常是由于Shell脚本文件中存在不兼容的换行符引起的。在Windows系统中&#…...

idea创建spring项目
一、环境 window10 IDEA 2022.2.3 maven-3.8.6 二、创建spring项目 1、新建Maven项目 File -> New -> Project 然后如下图选中Maven Archetype,在Archetype,选中maven-archetype-webapp,点击Create 2、配置maven 默认是使用IDEA内…...

【UE 材质】扇形材质
目录 效果 步骤 (1)控制扇形的弧宽度 (2)控制扇形的角度 (3)完整节点 效果 步骤 (1)控制扇形的弧宽度 创建一个材质,混合模式设置为“Additive”,着色…...
【react native】ScrollView的触摸事件与TouchableWithoutFeedback的点击事件冲突
需求背景 使用 ScrollView 组件实现轮播图效果,该轮播图可以自动向右滑动。有下面两个需求: (1)希望用户左右点击的时候,视图可以向左/向右滚动; (2)希望用户触摸在屏幕的时候&am…...

鸿蒙内核框架
1 内核概述 内核简介 用户最常见到并与之交互的操作系统界面,其实只是操作系统最外面的一层。操作系统最重要的任务,包括管理硬件设备,分配系统资源等,我们称之为操作系统内在最重要的核心功能。而实现这些核心功能的操作系统模…...

幻兽帕鲁专用服务器,多人游戏(专用服务器)搭建
玩转幻兽帕鲁服务器,阿里云推出新手0基础一键部署幻兽帕鲁服务器教程,傻瓜式一键部署,3分钟即可成功创建一台Palworld专属服务器,成本仅需26元,阿里云服务器网aliyunfuwuqi.com分享2024年新版基于阿里云搭建幻兽帕鲁服…...

7000字详解Spring Boot项目集成RabbitMQ实战以及坑点分析
本文给大家介绍一下在 Spring Boot 项目中如何集成消息队列 RabbitMQ,包含对 RibbitMQ 的架构介绍、应用场景、坑点解析以及代码实战。 我将使用 waynboot-mall 项目作为代码讲解,项目地址:https://github.com/wayn111/waynboot-mall。本文大…...

AJAX-认识URL
定义 概念:URL就是统一资源定位符,简称网址,用于访问网络上的资源 组成 协议 http协议:超文本传输协议,规定浏览器和服务器之间传输数据的格式;规定了浏览器发送及服务器返回内容的格式 协议范围…...

国图公考:公务员面试资格复审需要准备什么?
参加国考面试的考生在资格审核阶段需要准备以下材料: 1、本人身份证、学生证或工作证复印件。 2、公共科目笔试准考证复印件。 3、考试报名登记表。 4、本(专)科、研究生各阶段学历、学位证书(应届毕业生没有可以暂时不提供)。 5、报名资料上填写的各类证书材料…...

爬虫实战--人民网
文章目录 前言发现宝藏 前言 为了巩固所学的知识,作者尝试着开始发布一些学习笔记类的博客,方便日后回顾。当然,如果能帮到一些萌新进行新技术的学习那也是极好的。作者菜菜一枚,文章中如果有记录错误,欢迎读者朋友们…...
【Arduino】LGT8F328 UNO R3编译上传
LGT8F328 UNO R3编译上传 示例代码 这是一段示例代码,将示例代码编译打包上传到LGT8F328 UNO R3开发板。 #include <Servo.h> Servo myservo; int pos 0; void setup() {// put your setup code here, to run once:Serial.begin(9600);Serial.println(&qu…...

Python进阶----在线翻译器(Python3的百度翻译爬虫)
目录 一、此处需要安装第三方库requests: 二、抓包分析及编写Python代码 1、打开百度翻译的官网进行抓包分析。 2、编写请求模块 3、输出我们想要的消息 三、所有代码如下: 一、此处需要安装第三方库requests: 在Pycharm平台终端或者命令提示符窗口中输入以下代…...

ArcGISPro中Python相关命令总结
主要总结conda方面的相关命令 列出当前活动环境中的包 conda list 列出所有 conda 环境 conda env list 克隆环境 克隆以默认的 arcgispro-py3 环境为模版的 my_env 新环境。 conda create --clone arcgispro-py3 --name my_env --pinned 激活环境 activate my_env p…...

eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)
说明: 想象一下,你正在用eNSP搭建一个虚拟的网络世界,里面有虚拟的路由器、交换机、电脑(PC)等等。这些设备都在你的电脑里面“运行”,它们之间可以互相通信,就像一个封闭的小王国。 但是&#…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...

React19源码系列之 事件插件系统
事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...
面试高频问题
文章目录 🚀 消息队列核心技术揭秘:从入门到秒杀面试官1️⃣ Kafka为何能"吞云吐雾"?性能背后的秘密1.1 顺序写入与零拷贝:性能的双引擎1.2 分区并行:数据的"八车道高速公路"1.3 页缓存与批量处理…...
二维FDTD算法仿真
二维FDTD算法仿真,并带完全匹配层,输入波形为高斯波、平面波 FDTD_二维/FDTD.zip , 6075 FDTD_二维/FDTD_31.m , 1029 FDTD_二维/FDTD_32.m , 2806 FDTD_二维/FDTD_33.m , 3782 FDTD_二维/FDTD_34.m , 4182 FDTD_二维/FDTD_35.m , 4793...
node.js的初步学习
那什么是node.js呢? 和JavaScript又是什么关系呢? node.js 提供了 JavaScript的运行环境。当JavaScript作为后端开发语言来说, 需要在node.js的环境上进行当JavaScript作为前端开发语言来说,需要在浏览器的环境上进行 Node.js 可…...