【Java面试丨并发编程】线程中并发安全

一、Synchronized关键字的底层原理

1. Synchronized的作用

  • Synchronized【对象锁】采用互斥的方式让同一时刻至多只有一个线程能持有【对象锁】,其他线程再想获取这个【对象锁】时就会阻塞住

2. Monitor

  • Synchronized【对象锁】底层是由Monitor实现,线程获得锁时需要使用对象(锁)关联的Monitor
    在这里插入图片描述
  • Monitor被翻译为监视器,由JVM提供,C++语言实现,在Monitor内部有三个属性,分别为Owner、EntryList、WaitSet
    在这里插入图片描述
    (1)Owner:存储当前获取锁的线程,有且只能存储一个线程
    (2)EntryList:存储没有抢到锁的线程,此处均为处于Blocked阻塞状态的线程
    (3)WaitSet:存储调用wait()方法的线程,此处均为Waiting等待状态的线程

3. 锁升级

  • Java中的Synchronized有偏向锁、轻量级锁、重量级锁三种形式,分别对应了锁只被一个线程持有、不同线程交替持有锁、多线程竞争锁三种情况
  • 在JDK 1.6引入了两种新型锁机制:偏向锁和轻量级锁,它们的引入是为了解决在没有多线程竞争或基本没有竞争的场景下,因使用传统锁机制带来的性能开销问题
    在这里插入图片描述
  • 总结:一旦锁发生了竞争,都会升级为重量级锁

二、谈谈JMM(Java内存模型)

  • Java内存模型(Java Memory Model,JMM):定义了共享内存中多线程程序读写操作的行为规范,通过这些规则来规范对内存的读写操作,从而保证指令的正确性
    在这里插入图片描述
  • 总结
    (1)JMM把内存分为两块,一块是私有线程的工作区域(工作内存),另一块是所有线程的共享区域(主内存)
    (2)线程跟线程之间是相互隔离的,线程跟线程之间交互需要通过主内存

三、CAS你知道吗

1. 介绍

  • CAS(Compare And Swap,比较再交换):体现了一种乐观锁的思想,在无锁的情况下,能够保证线程操作共享数据的原子性
  • 在JUC(java.util.concurrent)包下实现的很多类都用到了CAS操作
    (1)AbstractQueuedSynchronizer(AQS框架)
    (2)AtomicXXX类(原子类)
  • 在操作共享变量的时候使用的是自旋锁,效率上更高一些
  • CAS的底层是调用Unsafe类中的方法,都是操作系统提供的,其他语言实现

2. CAS数据交换流程

在这里插入图片描述

3. 自旋锁

  • 第一次CAS失败后,通过自旋操作,会重新加载主内存中共享变量V值到线程的工作内存中,将A值覆盖为新的V值,然后再去CAS操作,直到成功为止
  • 自旋锁:因为没有加锁,所以线程不会陷入阻塞状态,效率较高;但是如果线程之间竞争激烈,重试频繁发生,效率会受影响
    在这里插入图片描述

4. CAS底层实现

  • CAS底层依赖于一个Unsafe类来直接调用操作系统底层的CAS指令
    在这里插入图片描述
  • ReentrantLock中实现CAS的代码
    在这里插入图片描述

5. 乐观锁和悲观锁

  • 乐观锁
    (1)CAS基于乐观锁的思想,最乐观的估计,不怕别的线程来修改共享变量,就算改了也没关系,我吃点亏再重试
  • 悲观锁
    (1)Synchronized基于悲观锁的思想,最悲观的估计,得防着其他线程来修改共享变量,我上了锁,你们都别想改,我改完了解开锁,你们才有机会修改

四、什么是AQS

1. 介绍

  • AQS(AbstractQueuedSynchronizer,抽象队列同步器):是构建锁或者其他同步组件的基础框架
  • AQS和Synchronized的区别
    在这里插入图片描述
  • AQS常见的实现类
    (1)ReentrantLock:阻塞式锁
    (2)Semaphore:信号量
    (3)CountDownLatch:倒计时锁

2. AQS工作机制

  • AQS内部维护了一个先进先出的双向队列,队列中存储着排队的线程
  • AQS内部还有一个属性state,这个state就相当于一个资源,默认是0(无锁状态)。如果队列中有一个线程成功修改state为1,则当前线程就相当于获取了资源(锁)
  • 基本工作机制
    在这里插入图片描述
  • 多个线程共同去抢这个state资源,如何保证原子性
    在这里插入图片描述
  • AQS是公平锁,还是非公平锁
    在这里插入图片描述

五、ReentrantLock的实现原理

1. 特点

  • ReentrantLock为可重入锁,相对于Synchronized锁具备以下特点
    (1)可中断
    (2)可以设置超时时间
    (3)可以设置公平锁
    (4)支持多个变量
    (5)与Synchronized锁一样,都支持重入,调用lock()方法获取到锁之后,再次调用lock()方法是不会阻塞的

2. 实现原理

  • ReentrantLock主要利用CAS+AQS队列来实现的,支持公平锁和非公平锁

  • ReentrantLock的构造方法接收一个可选的公平参数(默认:非公平锁),当设置为true时,表示公平锁,否则为非公平锁
    在这里插入图片描述

  • 公平锁的效率往往没有非公平锁效率高,在多线程访问的情况下,公平锁表现出较低的吞吐量

  • 具体描述
    在这里插入图片描述

六、死锁产生的条件是什么

1. 介绍

  • 死锁:一个线程需要同时获取多把锁,这时候就容易发生死锁
    在这里插入图片描述

2. 如何进行死锁诊断

  • 当程序出现了死锁现象,可以使用JDK自带的工具:jps和jstack
    (1)jps:输出JVM中运行的进程状态信息
    (2)jstack:查看Java进程内线程的堆栈信息
    在这里插入图片描述
  • 其他工具查看
    (1)jconsole.exe
    在这里插入图片描述
    (2)VisualVM
    在这里插入图片描述

七、谈谈你对volatile的理解

1. 介绍

  • 一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义
    (1)保证线程之间的可见性
    (2)禁止进行指令重排

2. 保证线程之间的可见性

  • 用volatile修饰共享变量,能够防止编译器等优化发生,让一个线程对共享变量的修改对另一个线程可见
  • 可见性问题分析:主要是因为在JVM虚拟机中有一个JIT(即时编译器)给代码做了优化
    在这里插入图片描述
    (1)解决方案一:在程序运行的时候加入VM参数-Xint,表示禁用JIT即时编译器【不推荐,得不偿失,其他程序还要使用JIT】
    (2)解决方案二:在修饰共享变量的时候加上volatile,告诉JIT不要对volatile修饰的变量做优化

3. 禁止指令重排序

  • 用volatile修饰共享变量时,会在读、写共享变量时加入不同的屏障,阻止其他读写操作越过屏障,从而达到阻止重排序的效果
  • 指令重排序演示
    在这里插入图片描述
  • 解决指令重排序演示
    在这里插入图片描述
  • volatile使用技巧
    (1)写变量:让volatile修饰的变量在代码最后位置
    (2)读变量:让volatile修饰的变量在代码最开始位置

八、聊一下ConcurrentHashMap

1. 介绍

  • ConcurrentHashMap是一种线程安全的高效Map集合
  • 底层数据结构
    (1)JDK 1.7:采用分段的数组+链表实现
    (2)JDK 1.8:采用的数据结构和HashMap一样,数组+链表/红黑二叉树

2. 添加数据逻辑

  • JDK 1.7:ReentrantLock锁+CAS
    (1)整体流程
    在这里插入图片描述
    (2)添加数据
    在这里插入图片描述
  • JDK 1.8:Synchronized锁+CAS
    (1)CAS控制数组节点的添加
    (2)Synchronized只是锁定当前链表/红黑树二叉树的首节点,只要hash不冲突,就不会产生并发问题,效率得到提升
    (3)添加数据
    在这里插入图片描述

九、导致并发程序出现问题的根本原因是什么

1. 原子性

  • 一个线程在CPU中操作不可暂停,也不可中断,要不执行完成,要不不执行

2. 可见性

  • 一个线程对共享变量的修改对另一个线程可见

3. 有序性

  • 指令重排序:处理器为了提高程序运行效率,可能会对输入代码进行优化。它不保证程序中各个语句的执行先后顺序与代码中的顺序一致

4. 解决方案

  • 原子性:Synchronized、Lock
  • 可见性:volatile、Synchronized、Lock
  • 有序性:volatile

十、Synchronized锁和Lock锁有什么区别

1. 语法层面

  • Synchronized是Java关键字,源码在JVM中,由C++语言实现
  • Lock是接口,源码由JDK提供,Java语言实现
  • 使用Synchronized时,退出同步代码块,锁会自动释放
  • 使用Lock时,需要手动调用unlock()方法释放锁

2. 功能层面

  • 二者均属于悲观锁,都具备基本的互斥、同步、锁重入功能
  • Lock提供了许多Synchronized不具备的功能,比如:公平锁、可打断(lock.lockInterruptibly()方法&t1.interrupt()方法)、可超时(lock.tryLock(long time)方法)、多条件变量(lock.newCondition()方法&c1.await()方法&c1.signal()方法)
  • Lock有适合不同场景的实现,比如:ReentrantLock、ReentrantReadWriteLock(读写锁)

3. 性能层面

  • 在没有竞争时候,Synchronized做了很多优化,性能不赖,比如:偏向锁、轻量级锁
  • 在竞争激烈时候,Lock的实现通常会提供更好的性能

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/27028.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机网络——VLan介绍

学习视频: 网工必会,十分钟搞明白,最常用的VLAN技术_哔哩哔哩_bilibili 技术总结:VLAN,网络中最常用的技术,没有之一_哔哩哔哩_bilibili 全国也没几个比我讲得好的:VLAN虚拟局域网 本来补充了…

巧妙使用 CSS 渐变来实现波浪动画

目录 一、波浪的原理 二、曲面的绘制 三、波浪动画 四、文字波浪动画 五、总结一下 参考资料 之前看到coco[1]的这样一篇文章:纯 CSS 实现波浪效果![2],非常巧妙,通过改变border-radius和不断旋转实现的波浪效果&#xff0c…

【unity细节】分不清楚__世界坐标,自身坐标,Vector3,transform和translate?

👨‍💻个人主页:元宇宙-秩沅 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 本文由 秩沅 原创 收录于专栏:unity细节和bug ⭐世界坐标系transform和自身坐标Trasform.local和Vector3⭐ 文章目录 ⭐世界坐标…

excel常用操作备忘

excel操作: 1、快速填充多列公式:选中多列后,按ctrlD填 充。 2、快速删除空行:全选行,按ctrlG,空值项前边打上钩,点确定,针对选中的空行,鼠标右击,点删除&…

APACHE KAFKA本机Hello World教程

目标 最近想要简单了解一下Apache Kafka,故需要在本机简单打个Kafka弄一弄Hello World级别的步骤。 高手Kafka大佬们,请忽略这里的内容。 步骤 Apacha Kafka要求按照Javak8以上版本的环境。从官网下载kafka并解压。 启动 # 生产kafka集群随机ID KA…

【机密计算标准】GB/T 41388-2022 可信执行环境基础安全规范

1 范围 本文件确立了可信执行环境系统整体技术架构,描述了可信执行环境基础要求、可信虚拟化系统、可信操作系统、可信应用与服务管理、跨平台应用中间件等主要内容及其测试评价方法。 2 规范性引用文件 下列文件中的内容通过文中的规范性引用面构成本文件必不…

❤️创意网页:如何创建一个漂亮的3D正六边形

✨博主:命运之光 🌸专栏:Python星辰秘典 🐳专栏:web开发(简单好用又好看) ❤️专栏:Java经典程序设计 ☀️博主的其他文章:点击进入博主的主页 前言:欢迎踏入…

Python多线程编程Queue队列使用方法

一、多线程编程Queue队列 在多线程编程中,由于多个线程并发执行,可能会导致线程之间出现协调问题,为了保证线程间的同步和协调,Python提供了Queue模块,支持多线程间的数据交换和同步。Queue是一种线程安全的数据结构&…

MYSQL常见面试题汇总

Yan-英杰的主页 悟已往之不谏 知来者之可追 C程序员,2024届电子信息研究生 目录 1、三大范式 2、DML 语句和 DDL 语句区别 3、主键和外键的区别 4、drop、delete、truncate 区别 5、基础架构 6、MyISAM 和 InnoDB 有什么区别? 7、推荐自增id作…

用 PerfView 洞察.NET程序非托管句柄泄露

一:背景 1. 讲故事 前几天写了一篇 如何洞察 .NET程序 非托管句柄泄露 的文章,文中使用 WinDbg 的 !htrace 命令实现了句柄泄露的洞察,在文末我也说了,WinDbg 是以侵入式的方式解决了这个问题,在生产环境中大多数情况…

深度学习(28)——YOLO系列(7)

深度学习(28)——YOLO系列(7) 咱就是说,需要源码请造访:Jane的GitHub:在这里 上午没写完的,下午继续,是一个小尾巴。其实上午把训练的关键部分和数据的关键部分都写完了…

青岛大学_王卓老师【数据结构与算法】Week05_07_顺序栈的操作1_学习笔记

本文是个人学习笔记,素材来自青岛大学王卓老师的教学视频。 一方面用于学习记录与分享, 另一方面是想让更多的人看到这么好的《数据结构与算法》的学习视频。 如有侵权,请留言作删文处理。 课程视频链接: 数据结构与算法基础…