当前位置: 首页 > news >正文

Java并发编程面试题——线程安全(原子性、可见性、有序性)

文章目录

  • 一、原子性高频问题
    • 1.1 Java中如何实现线程安全?
    • 1.2 CAS底层实现
    • 1.3 CAS的常见问题
    • 1.4 四种引用类型 + ThreadLocal的问题?
  • 二、可见性高频问题
    • 2.1 Java的内存模型
    • 2.2 保证可见性的方式
    • 2.3 volatile修饰引用数据类型
    • 2.4 有了MESI协议,为啥还有volatile?
    • 2.5 volatile的可见性底层实现
  • 三、有序性高频问题
    • 3.1 什么是有序性问题
    • 3.2 volatile的有序性底层实现
  • 四、synchronized高频问题
    • 4.1 synchronized锁升级的过程?
    • 4.2 synchronized锁粗化&锁消除?
    • 4.3 synchronized实现互斥性的原理?
    • 4.4 wait为什么是Object下的方法?

一、原子性高频问题

1.1 Java中如何实现线程安全?

线程安全问题:多线程操作共享数据出现的问题。

实现线程安全方式:

  • 悲观锁:synchronized,lock(AQS)
  • 乐观锁:CAS

可以根据业务情况,选择ThreadLocal,让每个线程玩自己的数据。

1.2 CAS底层实现

  • 先比较一下值是否与预期值一致,如果一致,交换,返回true
  • 先比较一下值是否与预期值一致,如果不一致,不交换,返回false

CAS在Java层面最多就能看到native方法,可以去看Unsafe类中提供的CAS操作

四个参数:哪个对象,哪个属性的内存偏移量,oldValue,newValue

image.png

native是直接调用本地依赖库C++中的方法。

unsafe源码:https://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/69087d08d473/src/share/vm/prims/unsafe.cpp

image.png

cmpxchg源码:https://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/69087d08d473/src/os_cpu/linux_x86/vm/atomic_linux_x86.inline.hpp
image.png

cmpxchg ,是汇编的指令,CPU硬件底层就支持 比较和交换 (cmpxchg),cmpxchg并不保证原子性的,如果是多核的操作系统,需要追加一个lock指令。

lock指令可以理解为是CPU层面的锁,一般锁的粒度就是 缓存行 级别的锁,当然也有 总线锁 ,但是成本太高,CPU会根据情况选择。

1.3 CAS的常见问题

  1. ABA问题: ABA不一定是问题!因为一些只存在 ++,–的这种操作,即便出现ABA问题,也不影响结果!

    比如说一个线程one从内存位置V中取出A,这时候另一个线程two也从内存中取出A,并且two进行了一些操作变成了B,然后two又将V位置的数据变成A,这时候线程one进行CAS操作发现内存中仍然是A,然后one操作成功。

    解决方案很简单,Java端已经提供了,JUC下提供的AtomicStampedReference就可以实现。修改value的同时,指定好版本号,一旦版本号和数据的版本号不一致就执行失败。
    image.png

  2. 自旋次数过多问题:自旋次数过多,会额外的占用大量的CPU资源!浪费资源。

    解决方案:

    • synchronized方向:从CAS几次失败后,就将线程挂起(WAITING),避免占用CPU过多的资源!
    • LongAdder方向:这里是基于类似 分段锁 的形式去解决(要看业务,有限制的),传统的AtmoicLong是针对内存中唯一的一个值去++,LongAdder在内存中搞了好多个值,多个线程去加不同的值,当你需要结果时,我将所有值累加,返回给你。
  3. 只针对一个属性保证原子性

1.4 四种引用类型 + ThreadLocal的问题?

ThreadLocal的问题:见Java基础面试题——IO和多线程专题

四种引用类型:

  • 强引用:User xx = new User(); xx就是强引用,只要引用还在,GC就不会回收!

  • 软引用:用一个SofeReference引用的对象,就是软引用,如果内存空间不足,才会回收只有软引用指向对象。 一般用于做缓存

    SoftwareReference xx = new SoftwareReference (new User);User user = xx.get();
    
  • 弱引用:WeakReference引用的对象,一般就是弱引用,只要执行GC,就会回收只有弱引用指向的对象。可以解决内存泄漏的问题 ,看ThreadLocal即可

  • 虚引用:PhantomReference引用的对象,就是虚引用,拿不到虚引用指向的对象,一般监听GC回收阶段,或者是回收堆外内存时使用。

二、可见性高频问题

2.1 Java的内存模型

在处理指令时,CPU会拉取数据,优先级是从L1(线程独享)到L2(内核独享)到L3(多核共享),如果都没有,需要去主内存中拉取,JMM就是在CPU和主内存之间,来协调,保证可见、有序性等操作。

Java Memory Model
image.png

2.2 保证可见性的方式

啥是可见性: 可见性是指线程间的,对变量的变化是否可见。

Java层面中,保证可见性的方式有很多:

  • volatile,用volatile基本数据类型,可以保证每次CPU去操作数据时,都直接去主内存进行读写。
  • synchronized,synchronized的内存语义可以保证在获取锁之后,可以保证前面操作的数据是可见的。
  • lock(CAS-volatile),也可以保证CAS或者操作volatile的变量之后,可以保证前面操作的数据是可见的。
  • final,是常量没法动~~。

2.3 volatile修饰引用数据类型

volatile修饰引用数据类型,只能保证引用数据类型的地址是可见的,不保证内部属性可见。

2.4 有了MESI协议,为啥还有volatile?

MESI是CPU缓存一致性的协议,大多数的CPU厂商都根据MESI去实现了缓存一致性的效果。

MESI协议和volatile不冲突,因为MESI是CPU层面的,而CPU厂商很多实现不一样,而且CPU的架构中的一些细节也会有影响,比如Store Buffer会影响寄存器写入L1缓存,导致缓存不一致。volatile的底层生成的是汇编的lock指令,这个指令会要求强行写入主内存,并且可以忽略Store Buffer这种缓存从而达到可见性的目的,而且会利用MESI协议,让其他缓存行失效。当然,如果没有MESI协议,volatile也会存在一些问题。

2.5 volatile的可见性底层实现

volatile的底层生成的是汇编的lock指令,这个指令会要求强行写入主内存,并且可以忽略Store Buffer这种缓存从而达到可见性的目的,而且会利用MESI协议,让其他缓存行失效。

三、有序性高频问题

3.1 什么是有序性问题

在Java编译.java为.class时,会基于JIT做优化,将指令的顺序做调整,从而提升执行效率。在CPU层面,也会对一些执行进行重新排序,从而提升执行效率。这种指令的调整,在一些特殊的操作上,会导致出现问题。

单例模式中的懒汉机制中,就存在一个这样的问题。懒汉为了保证线程安全,一般会采用DCL的方式。

3.2 volatile的有序性底层实现

被volatile修饰的属性,在编译时,会在前后追加 内存屏障 ,这个内存屏障是JDK规定的,目的是保证volatile修饰的属性不会出现指令重排的问题。

Store Store:屏障前的读写操作,必须全部完成,再执行后续操作

Store Load:屏障前的写操作,必须全部完成,再执行后续读操作

Load Load:屏障前的读操作,必须全部完成,再执行后续读操作

Load Store:屏障前的读操作,必须全部完成,再执行后续写操作

image.png

volatile在JMM层面,保证JIT不重排可以理解,但是,CPU怎么实现的,
查看这个文档:https://gee.cs.oswego.edu/dl/jmm/cookbook.html

image.png

不同的CPU对内存屏障都有一定的支持,比如×86架构,内部自己已经实现了LS,LL,SS,只针对SL做了支持。

去openJDK再次查看,mfence是如何支持的。其实在底层还是mfence内部的lock指定,来解决指令重排问题。

image.png

四、synchronized高频问题

4.1 synchronized锁升级的过程?

锁就是对象,随便哪一个都可以,Java中所有对象都是锁。

升级过程:无锁(匿名偏向)->偏向锁->轻量级锁->重量级锁

无锁(匿名偏向): 一般情况下,new出来的一个对象,是无锁状态。因为偏向锁有延迟,在启动JVM的4s中,不存在偏向锁,但是如果关闭了偏向锁延迟的设置,new出来的对象,就是匿名偏向。

偏向锁: 当某一个线程来获取这个锁资源时,此时,就会变为偏向锁,偏向锁存储线程的ID,当偏向锁升级时,会触发偏向锁撤销,偏向锁撤销需要等到一个安全点,比如GC的时候,偏向锁撤销的成本太高,所以默认开始时,会做偏向锁延迟。

安全点:

  • GC
  • 方法返回之前
  • 调用某个方法之后
  • 甩异常的位置
  • 循环的末尾

轻量级锁: 当在出现了多个线程的竞争,就要升级为轻量级锁(有可能直接从无锁变为轻量级锁,也有可能从偏向锁升级为轻量级锁),轻量级锁的效果就是基于CAS尝试获取锁资源,这里会用到自适应自旋锁,根据上次CAS成功与否,决定这次自旋多少次。

重量级锁: 如果到了重量级锁,如果有线程持有锁,其他竞争的,就挂起。

4.2 synchronized锁粗化&锁消除?

锁粗化(锁膨胀):(JIT优化)

while(){sync(){// 多次的获取和释放,成本太高,优化为下面这种}
}
//----
sync(){while(){//  优化成这样}
}

锁消除:在一个sync中,没有任何共享资源,也不存在锁竞争的情况,JIT编译时,就直接将锁的指令优化掉。

4.3 synchronized实现互斥性的原理?

偏向锁:查看对象头中的MarkWord里的线程ID,是否是当前线程,如果不是,就CAS尝试改,如果是,就拿到了锁资源。

轻量级锁:查看对象头中的MarkWord里的Lock Record指针指向的是否是当前线程的虚拟机栈,如果是,拿锁执行业务,如果不是CAS,尝试修改,修改他几次,不成,再升级到重量级锁。

重量级锁:查看对象头中的MarkWord里的指向的ObjectMonitor,查看owner是否是当前线程,如果不是,扔到ObjectMonitor里的EntryList中,排队,并挂起线程,等待被唤醒。

image.png

4.4 wait为什么是Object下的方法?

  1. wait方法是在持有sync锁的时候释放锁资源。
  2. sync锁的是对象也就是Object。
  3. 所以wait自然是Object下的方法。

相关文章:

Java并发编程面试题——线程安全(原子性、可见性、有序性)

文章目录一、原子性高频问题1.1 Java中如何实现线程安全?1.2 CAS底层实现1.3 CAS的常见问题1.4 四种引用类型 ThreadLocal的问题?二、可见性高频问题2.1 Java的内存模型2.2 保证可见性的方式2.3 volatile修饰引用数据类型2.4 有了MESI协议,为啥还有vol…...

DialogFragment内存泄露问题能不能一次性改好

孽缘 自DialogFragment在Android3.0之后作为一种特殊的Fragment引入,官方建议使用DialogFragment代替Dialog或者AllertDialog来实现弹框的功能,因为它可以更好的管理Dialog的生命周期以及可以更好复用。 然而建议虽好,实用须谨慎&#xff0c…...

java学习--多线程

多线程 了解多线程 ​ 多线程是指从软件或者硬件上实现多个线程并发执行的技术。 ​ 具有多线程能力的计算机因有硬件支持而能够在同一时间执行多个线程,提升性能。 并发和并行 并行:在同一时刻,有多个指令在CPU上同时执行并发&#xff1…...

90后阿里P7技术专家晒出工资单:狠补了这个,真香...

最近一哥们跟我聊天装逼,说他最近从阿里跳槽了,我问他跳出来拿了多少?哥们表示很得意,说跳槽到新公司一个月后发了工资,月入5万多,表示很满足!这样的高薪资着实让人羡慕,我猜这是税后…...

2023美赛C题:Wordle筛选算法

Wordle 规则介绍 Wordle 每天会更新一个5个字母的单词,在6次尝试中猜出单词就算成功。每个猜测必须是一个有效的单词(不能是不能组成单词的字母排列)。 每次猜测后,字母块的颜色会改变,颜色含义如下: 程…...

SpringBoot 集成 Kafka

SpringBoot 集成 Kafka1 安装 Kafka2 创建 Topic3 Java 创建 Topic4 SpringBoot 项目4.1 pom.xml4.2 application.yml4.3 KafkaApplication.java4.4 CustomizePartitioner.java4.5 KafkaInitialConfig.java4.6 SendMessageController.java5 测试1 安装 Kafka Docker 安装 Kafk…...

OpenCV 图像金字塔算子

本文是OpenCV图像视觉入门之路的第14篇文章,本文详细的介绍了图像金字塔算子的各种操作,例如:高斯金字塔算子 、拉普拉斯金字塔算子等操作。 高斯金字塔中的较高级别(低分辨率)是通过先用高斯核对图像进行卷积再删除偶…...

【自学Linux】Linux一切皆文件

Linux一切皆文件 Linux一切皆文件教程 Linux 中所有内容都是以文件的形式保存和管理的,即一切皆文件,普通文件是文件,目录是文件,硬件设备(键盘、监视器、硬盘、打印机)是文件,就连套接字&…...

CUDA C++扩展的详细描述

CUDA C扩展的详细描述 文章目录CUDA C扩展的详细描述CUDA函数执行空间说明符B.1.1 \_\_global\_\_B.1.2 \_\_device\_\_B.1.3 \_\_host\_\_B.1.4 Undefined behaviorB.1.5 __noinline__ and __forceinline__B.2 Variable Memory Space SpecifiersB.2.1 \_\_device\_\_B.2.2. \_…...

为什么重写equals必须重写hashCode

关于这个问题,看了网上很多答案,感觉都参差不齐,没有答到要点,这次就记录一下! 首先我们为什么要重写equals?这个方法是用来干嘛的? public boolean equals (Object object&#x…...

< 每日小技巧:N个很棒的 Vue 开发技巧, 持续记录ing >

每日小技巧:6 个很棒的 Vue 开发技巧👉 ① Watch 妙用> watch的高级使用> 一个监听器触发多个方法> watch 监听多个变量👉 ② 自定义事件 $emit() 和 事件参数 $event👉 ③ 监听组件生命周期常规写法hook写法&#x1f44…...

数据结构与算法之二分查找分而治之思想

决定我们成为什么样人的,不是我们的能力,而是我们的选择。——《哈利波特与密室》二分查找是查找算法里面是很优秀的一个算法,特别是在有序的数组中,这种算法思想体现的淋漓尽致。一.题目描述及其要求请实现无重复数字的升序数组的…...

训练自己的中文word2vec(词向量)--skip-gram方法

训练自己的中文word2vec(词向量)–skip-gram方法 什么是词向量 ​ 将单词映射/嵌入(Embedding)到一个新的空间,形成词向量,以此来表示词的语义信息,在这个新的空间中,语义相同的单…...

ubuntu系统环境配置和常用软件安装

系统环境 修改文件夹名称为英文 参考链接 export LANGen_US xdg-user-dirs-gtk-update 常用软件安装 常用工具 ping 和ifconfig工具 sudo apt install -y net-tools inetutils-ping 截图软件 sudo apt install -y net-tools inetutils-ping flameshot 录屏 sudo apt-get i…...

【1139. 最大的以 1 为边界的正方形】

来源:力扣(LeetCode) 描述: 给你一个由若干 0 和 1 组成的二维网格 grid,请你找出边界全部由 1 组成的最大 正方形 子网格,并返回该子网格中的元素数量。如果不存在,则返回 0。 示例 1&#…...

windows11安装sqlserver2022报错

window11安装SQL Server 2022 报错 糟糕… 无法安装SQL Server (setup.exe)。此 SQL Server安装程序介质不支持此OS的语言,或没有SQL Server英语版本的安装文件。请使用匹配的特定语言SQL Server介质;或安装两个特定语言MUI,然后通过控制面板的区域设置…...

Python快速上手系列--日志模块--详解篇

前言本篇主要说说日志模块,在写自动化测试框架的时候我们就需要用到这个模块了,方便我们快速的定位错误,了解软件的运行情况,更加顺畅的调试程序。为什么要用到日志模块,直接print不就好了!那得写多少print…...

【THREE.JS学习(1)】绘制一个可以旋转、放缩的立方体

学习新技能,做一下笔记。在使用ThreeJS的时候,首先创建一个场景const scene new THREE.Scene();接着,创建一个相机其中,THREE.PerspectiveCamera()四个参数分别为:1.fov 相机视锥体竖直方向视野…...

数仓实战 - 滴滴出行

项目大致流程: 1、项目业务背景 1.1 目的 本案例将某出行打车的日志数据来进行数据分析,例如:我们需要统计某一天订单量是多少、预约订单与非预约订单的占比是多少、不同时段订单占比等 数据海量 – 大数据 hive比MySQL慢很多 1.2 项目架…...

python虚拟环境与环境变量

一、环境变量 1.环境变量 在命令行下,使用可执行文件,需要来到可执行文件的路径下执行 如果在任意路径下执行可执行文件,能够有响应,就需要在环境变量配置 2.设置环境变量 用户变量:当前用户登录到系统,…...

BeautifulSoup文档4-详细方法 | 用什么方法对文档树进行搜索?

4-详细方法 | 用什么方法对文档树进行搜索?1 过滤器1.1 字符串1.2 正则表达式1.3 列表1.4 True1.5 可以自定义方法2 find_all()2.1 参数原型2.2 name参数2.3 keyword 参数2.4 string 参数2.5 limit 参数2.6 recursive 参数3 find()4 find_parents()和find_parent()5…...

初识Tkinter界面设计

目录 前言 一、初识Tkinter 二、Label控件 三、Button控件 四、Entry控件 前言 本文简单介绍如何使用Python创建一个界面。 一、初识Tk...

软件测试面试题中的sql题目你会做吗?

目录 1.学生表 2.一道SQL语句面试题,关于group by表内容: 3.表中有A B C三列,用SQL语句实现:当A列大于B列时选择A列否则选择B列,当B列大于C列时选择B列否则选择C列 4. 5.姓名:name 课程:subject 分数&…...

VS实用调试技巧

一.什么是BUG🐛Bug一词的原意是虫子,而在电脑系统或程序中隐藏着的一些未被发现的缺陷或问题,人们也叫它"bug"。这是为什么呢?这就要追溯到一个程序员与飞蛾的故事了。Bug的创始人格蕾丝赫柏(Grace Murray H…...

通俗易懂理解三次握手、四次挥手(TCP)

文章目录1、通俗语言理解1.1 三次握手1.2 四次挥手2、进一步理解三次握手和四次挥手2.1 三次握手2.2 四次挥手1、通俗语言理解 1.1 三次握手 C:客户端 S:服务器端 第一次握手: C:在吗?我要和你建立连接。 第二次握手&#xff…...

1.1 什么是并发

1.1 什么是并发 并发:指两个或更多独立的活动同时发生。并发在生活中随处可见。我们可以一边走路一边说话,也可以两只手同时做不同的动作。 1.1.1 计算机系统中的并发 当我们提到计算机术语的“并发”,指的是在单个系统里同时执行多个独立…...

万字讲解你写的代码是如何跑起来的?

今天我们来思考一个简单的问题&#xff0c;一个程序是如何在 Linux 上执行起来的&#xff1f; 我们就拿全宇宙最简单的 Hello World 程序来举例。 #include <stdio.h> int main() {printf("Hello, World!\n");return 0; } 我们在写完代码后&#xff0c;进行…...

034.Solidity入门——21不可变量

Solidity 中的不可变量是在编译时就被确定的常量&#xff0c;也称为常量变量&#xff08;constant variable&#xff09;或只读变量&#xff08;read-only variable&#xff09;。这些变量在定义时必须立即初始化&#xff0c;并且在整个合约中都无法被修改&#xff0c;可以在函…...

Vulnhub 渗透练习(四)—— Acid

环境搭建 环境下载 kail 和 靶机网络适配调成 Nat 模式&#xff0c;实在不行直接把网络适配还原默认值&#xff0c;再重试。 信息收集 主机扫描 没扫到&#xff0c;那可能端口很靠后&#xff0c;把所有端口全扫一遍。 发现 33447 端口。 扫描目录&#xff0c;没什么有用的…...

C++ 在线工具

online编译器https://godbolt.org/Online C Compiler - online editor (onlinegdb.com) https://www.onlinegdb.com/online_c_compilerC Shell (cpp.sh) https://cpp.sh/在线文档Open Standards (open-std.org)Index of /afs/cs.cmu.edu/academic/class/15211/spring.96/wwwC P…...

什么网站做装修的/链接买卖

前言 在微服务实战&#xff1a;基于Spring Cloud Gateway AWS Cognito 的BFF案例一文中&#xff0c; 介绍了基于Amazon Cognito的OAuth授权码模式的认证流程。本文中&#xff0c;我们将研究可能针对此流程的恶意攻击以及如何防止它们。你将了解如何使用状态随机数&#xff08…...

30岁学编程还能找到工作吗/关键词优化快速

1,CDC::SelectObject出错&#xff1a; 昨天写了一个画图程序&#xff0c;发现执行到SelectObject(pOldPen)的时候老是出错&#xff0c;找了半天都没发现是什么问题&#xff0c;后来在csdn里讲可能是在SelectObject(&pen)的时候少了个取地址符&#xff0c;再次检查&#xff…...

烟台食品公司中企动力提供网站建设/seo免费优化软件

根据时间计算星座 // 计算当前日期星座getHoroscope(date) {let c [摩羯,水瓶,双鱼,白羊,金牛,双子,巨蟹,狮子,处女,天秤,天蝎,射手,摩羯]datenew Date(date);let month date.getMonth() 1;let day date.getDate();let startMonth month - (day - 14 < 865778999988.c…...

站长工具最近查询/广东企业网站seo哪里好

2019独角兽企业重金招聘Python工程师标准>>> Logback日志使用说明 项目跑了几个月了、测试服务器一直报空间不足、公司很小也没有运维。登上去查看以后发现log日志文件上百G并且很多都是没用的。所以下午简单查看了一下日志文件的配置。 没有优化后的logback.xml配置…...

wordpress手机端慢/torrent种子猫

我使用的是asp.net core 2.2.8&#xff0c;已安装aspnetcore-runtime-2.2.8-win-x64.exe与dotnet-runtime-2.2.8-win-x64.exe&#xff0c;相关设置已配置完毕。IIS服务安装启用正常。 网页搜索发现&#xff0c;是因为AspNetCoreModule这个组件未安装。 //2.2.x 下载地址 http…...

商城网站 前置审批/深圳网站快速排名优化

题目描述 R国和 S国正陷入战火之中&#xff0c;双方都互派间谍&#xff0c;潜入对方内部&#xff0c;伺机行动。历尽艰险后&#xff0c;潜伏于 S国的 R 国间谍小 C终于摸清了 S 国军用密码的编码规则&#xff1a; 1&#xff0e; S 国军方内部欲发送的原信息经过加密后在网络上…...