我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Java面试题之并发编程的示例分析

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Java面试题之并发编程的示例分析

小编给大家分享一下Java面试题之并发编程的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!

面试题1:说一下你对ReentrantLock的理解?

ReentrantLock是JDK1.5引入的,它拥有与synchronized相同的并发性和内存语义,并提供了超出synchonized的其他高级功能(例如,中断锁等候、条件变量等),并且使用ReentrantLock比synchronized能获得更好的可伸缩性。

ReentrantLock主要利用: CAS(compare-and-swap) + AQS(AbstractQueuedSynchronizer)队列来实现。它支持公平锁和非公平锁,两者的实现类似。

CAS:

CAS(compare-and-swap),见名知意,比较并交换。CAS 加 volatile 关键字是实现并发包的基石。没有CAS就不会有并发包,synchronized是一种独占锁、悲观锁,java.util.concurrent中借助了CAS指令实现了一种区别于synchronized的一种乐观锁。

CAS引用了乐观锁思想,每次拿数据的时候都认为别的线程不会修改这个数据,所以不会上锁,但是在更新的时候会通过标记参数判断一下在此期间(更新期间)别的线程有没有已经修改过该标记数据,如果发现有其他线程在修改且未修改完成,并不会像悲观锁那样阻塞线程,而是直接返回,可以去选择再次重试获得锁,也可以直接退出。

举个流程示例

如CAS操作包括三个操作数:需要读写的内存位置(V)、预期原值(A)、新值(B)。如果内存位置与预期原值的A相匹配,说明在此期间(更新期间)别的线程未修改过该标记数据,那么将内存位置的值更新为新值B。如果内存位置与预期原值的值不匹配,那么处理器不会做任何操作。

无论哪种情况,它都会在 CAS 指令之前返回该位置的值。(在 CAS 的一些特殊情况下将仅返回 CAS 是否成功,而不提取当前值。)

AQS:

AQS主要利用硬件原语指令CAS,来实现轻量级多线程同步机制,并且不会引起CPU上文切换和调度,同时提供内存可见性和原子化更新保证(线程安全的三要素:原子性、可见性、顺序性)。

AQS的本质上是一个同步器/阻塞锁的基础框架,其作用主要是提供加锁、释放锁,并在内部维护一个FIFO等待队列,用于存储由于锁竞争而阻塞的线程。

追问1:你认为 ReentrantLock 相比 synchronized 都有哪些区别?

优秀问答摘自:https://ask.csdn.net/questions/1101634

两者的共同点:

  • 都是用来协调多线程对共享对象、变量的访问

  • 都是可重入锁,同一线程可以多次获得同一个锁

  • 都保证了可见性和互斥性

两者的不同点:

  • ReentrantLock 显示的获得、释放锁,synchronized 隐式获得释放锁;

  • ReentrantLock 可响应中断、可轮回,synchronized 是不可以响应中断的,为处理锁的不可用性提供了更高的灵活性;

  • ReentrantLock 是API 级别的,synchronized 是 JVM 级别的;

  • ReentrantLock 可以实现公平锁;

  • ReentrantLock 通过 Condition 可以绑定多个条件;

  • 底层实现不一样, synchronized 是同步阻塞,使用的是悲观并发策略,ReentrantLock 是同步非阻塞,采用的是乐观并发策略;

  • Lock 是一个接口,而 synchronized 是 Java 中的关键字,synchronized 是内置的语言实现;

  • synchronized 在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;

  • 而 Lock 在发生异常时,如果没有主动通过 unLock()去释放锁,则很可能造成死锁现象,因此使用 Lock 时需要在 finally 块中释放锁。

Lock lock = new ReentrantLock();Condition condition = lock.newCondition();lock.lock();try {  while(条件判断表达式) {      condition.wait();  } // 处理逻辑} finally {    lock.unlock();}
  • Lock 可以让等待锁的线程响应中断,而 synchronized 却不行,使用 synchronized 时,等待的线程会一直等待下去,不能够响应中断。

  • 通过 Lock 可以知道有没有成功获取锁,而 synchronized 却无法办到。

  • Lock 可以提高多个线程进行读操作的效率,就是实现读写锁等。

面试题2:解释一下公平锁和非公平锁?

ReenTrantLock可以指定是公平锁还是非公平锁,而synchronized只能是非公平锁。所谓的公平锁就是先等待的线程先获锁。

我们刚才提及到AQS中,如果线程A正处于lock状态,线程B进来时发现线程A处于lock状态,会自动进入阻塞队列,等待取锁;这时候当线程C也进来了也发现线程A处于lock状态,也会自动进入阻塞队列。那么等A释放锁后,下次加锁到底是线程B先拿到还是线程C先拿到呢?

Java面试题之并发编程的示例分析

ReentrantLock有个构造方法用于设置锁的公平性,如果我们仅仅是new了一个ReentrantLock的话,那么就是非公平锁(默认),就是靠自己去争取,完全的随机性。如果我们在new ReentrantLock(true) 加入 true参数时,公平锁,就会遵循先入先出的原则,保证了锁的公平性。

面试题3:能详细说一下CAS具体实现原理么?

首先,CAS的英文单词是Compare and Swap,即是比较并替换。CAS机制中使用了3个基本操作数:内存地址V,旧的预期值A,待替换的新值B。

CAS规则是:当需要更新一个变量的值的时候,只有当变量的预期值A和内存地址V中的实际值相同的时候,才会把内存地址V对应的值替换成B。

下面我们通过一个例子来讲解:

在内存地址V中存储的值是陈哈哈

Java面试题之并发编程的示例分析

线程01想要把变量的值改成侨总,对于线程01而言,内存地址 V=‘陈哈哈',旧的预期值 A=‘陈哈哈',需要替换的新值 B=‘侨总'。

Java面试题之并发编程的示例分析

在线程01要提交更新之前,另外一个线程02抢先一步,将内存地址V中的值更新成了V='比特币'。

Java面试题之并发编程的示例分析

线程01开始提交更新的时候,按照CAS机制,首先进行A的值与内存地址V中的值进行比较( A=‘陈哈哈' V=‘比特币'),发现 A != V 中的实际值,提交失败。

Java面试题之并发编程的示例分析

线程01未获取锁后进行重试,重新获取内存地址V的当前值(V=‘比特币'),并重新赋值想要修改的值(B=‘侨总')。截至目前,线程01旧的预期值为A='比特币',B='侨总',这个重新尝试的过程被称为自旋。

Java面试题之并发编程的示例分析

这一次就比较顺利了,没有其他线程改变该变量的值,所以线程01通过CAS机制,比较旧的预期值A与内存地址V的值,相同(V == A),可以替换。

Java面试题之并发编程的示例分析

线程01进行替换,把地址V(V=‘比特币')的值替换成B(B=‘侨总')。

Java面试题之并发编程的示例分析

  以上就是一个比较完整的CAS锁冲突的处理方式。

  从思想上来看,synchronized属于悲观锁,悲观的认为程序中的并发问题十分严重,所以严防死守,只让一个线程操作该代码块。而CAS属于乐观锁,乐观地认为程序中的并发问题并不那么严重,所以让线程不断的去尝试更新,在并发问题不严重的时候性能要比synchronized快。

追问1:那CAS的缺陷有哪些呢?

当然,CAS也有缺点,如ABA问题,自旋锁消耗问题、多变量共享一致性问题等。

1.ABA:

问题描述:

线程t1将它的值从A变为B,再从B变为A。同时有线程t2要将值从A变为C。但CAS检查的时候会发现没有改变,但是实质上它已经发生了改变 。可能会造成数据的缺失。

解决方法:

CAS还是类似于乐观锁,同数据乐观锁的方式给它加一个版本号或者时间戳,如AtomicStampedReference

2.自旋消耗资源:

问题描述:

多个线程争夺同一个资源时,如果自旋一直不成功,将会一直占用CPU。

解决方法:

破坏掉for死循环,当超过一定时间或者一定次数时,return退出。JDK8新增的LongAddr,和ConcurrentHashMap类似的方法。当多个线程竞争时,将粒度变小,将一个变量拆分为多个变量,达到多个线程访问多个资源的效果,最后再调用sum把它合起来。

虽然base和cells都是volatile修饰的,但感觉这个sum操作没有加锁,可能sum的结果不是那么精确。

3.多变量共享一致性问题:

解决方法:

CAS操作是针对一个变量的,如果对多个变量操作,

  • 可以加锁来解决。

  • 封装成对象类解决。

追问2:讲一下什么是ABA问题?怎么解决?

ABA:如果另一个线程修改V值假设原来是A,先修改成B,再修改回成A。当前线程的CAS操作无法分辨当前V值是否发生过变化。

举个例子1:

例一:你和女神一起喝茶,女神喝了一半去厕所了,你猥琐的喝了她剩下的半杯,然后又从你杯子里倒了半杯给她,女神回来后也不知道是否被人喝过。

如果觉得例子1太猥琐的话,请看例子2:

例二:

今天上午10:30:00:我银行卡有一万块钱,今天我来ATM机取5000块出来买比特币,但由于ATM机硬件问题,导致取款操作同时提交了两遍,后台开启了两个线程(线程1、线程2),两个线程都是获取当前值10000元,要更新成5000元;理想情况下,应该一个线程更新成功,一个线程更新失败,我的存款只扣除一次,也就是余额应为5000元 。

好巧不巧,也是今天上午10:30:00:侨总上次买币欠我5000块,经过我再三催债,表示再不还钱就把你买币的事儿告诉你媳妇!也正巧这个点儿,侨总给我转了5000元到卡里(线程3)。没想到这再正常不过的事儿,缺被ABA问题坑了!我可忍不了!

事情是这样的:

线程1首先执行成功,把余额10000更新为5000(取钱线程)。同时线程2由于某种原因陷入了阻塞状态(取钱线程)。这时候,(线程3)侨总汇款给了我5000元,执行成功,我的账户5000更新为10000元。过一会儿,线程2恢复运行,由于之前阻塞的时候获得了当前值为:10000,并且经过compare检测,此时存款也的确是10000元,所以又成功把变量值从10000更新成了5000。侨总:哈哥,5000给你打过去了!我:查到账户只有5000,你他娘的糊弄老子呢??侨总:???我好几十个比特币的人,还在乎你这5000块钱了。。。

这就是经典的 A → B → A 问题,通过上面的例子,相信同学们也基本了解它的原理了。其实解决方式也很简单,比如例一,我们将每一次倒水假设有一个自动记录仪记录下,这样主人回来就可以分辨在她离开后是否发生过重新倒满的情况。这也是解决ABA问题目前采用的策略。

使用版本号,通过比较值 + 版本号才判断是否可以替换。这么看来如果要解决ABA问题,就需要在CAS基础上在增加一个版本号的校验,当值 + 版本号都相等时,才进行替换,其他部分均不变。

而在Java中,AtomicStampedReference类就实现了用版本号做比较的CAS机制。

看完了这篇文章,相信你对“Java面试题之并发编程的示例分析”有了一定的了解,如果想了解更多相关知识,欢迎关注编程网行业资讯频道,感谢各位的阅读!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Java面试题之并发编程的示例分析

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Java面试题之并发编程的示例分析

小编给大家分享一下Java面试题之并发编程的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!面试题1:说一下你对ReentrantLock的理解?ReentrantLock是JDK1.5引入的,它拥有与synchro
2023-06-20

Java并发编程之线程池的示例分析

这篇文章将为大家详细讲解有关Java并发编程之线程池的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。什么是线程池是一种基于池化思想管理线程的工具。池化技术:池化技术简单点来说,就是提前保存大量的资
2023-06-20

Java并发面试题实例分析

这篇文章主要讲解了“Java并发面试题实例分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java并发面试题实例分析”吧!题目结论多线程并发的同时进行set、get操作, A线程调用set
2023-06-05

Java面试题之JVM的示例分析

这篇文章给大家分享的是有关Java面试题之JVM的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。面试题1:你遇到过哪些OOM情况,什么原因造成的?怎么解决的?该问题主要针对你遇到的实际问题出发,可以根据你
2023-06-20

Java并发编程之ConcurrentLinkedQueue源码的示例分析

这篇文章给大家分享的是有关Java并发编程之ConcurrentLinkedQueue源码的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、ConcurrentLinkedQueue介绍并编程中,一般需
2023-06-15

Java面试题之算法的示例分析

小编给大家分享一下Java面试题之算法的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!面试题1:你说一下常用的排序算法都有哪些?追问1:谈一谈你对快排的理
2023-06-20

Java面试题之分布式的示例分析

这篇文章主要为大家展示了“Java面试题之分布式的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Java面试题之分布式的示例分析”这篇文章吧。面试题1:说说什么分布式事务?解释一下什么是
2023-06-20

Java并发编程之Fork/Join框架的示例分析

这篇文章主要介绍了Java并发编程之Fork/Join框架的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。一、Fork/Join框架的理解ForkJoinTask类属
2023-06-15

Java并发编程之关键字volatile的示例分析

这篇文章给大家分享的是有关Java并发编程之关键字volatile的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、作用被 volatile 修饰的变量1.保证了不同线程对该变量操作的内存可见性2.禁止
2023-06-15

Java并发编程之同步容器与并发容器的示例分析

这篇文章主要为大家展示了“Java并发编程之同步容器与并发容器的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Java并发编程之同步容器与并发容器的示例分析”这篇文章吧。一、同步容器 1
2023-06-15

Java面试题之手撸算法的示例分析

这篇文章将为大家详细讲解有关Java面试题之手撸算法的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。手撸算法1:查找数组中重复元素和重复元素的个数当听让我写这个算法时,纸笔还没给到我手上,作为一个
2023-06-20

Java之JMM高并发编程实例分析

这篇文章主要介绍“Java之JMM高并发编程实例分析”,在日常操作中,相信很多人在Java之JMM高并发编程实例分析问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java之JMM高并发编程实例分析”的疑惑有所
2023-07-02

Go并发编程的示例分析

这篇文章给大家分享的是有关Go并发编程的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、goroutine定义给函数前加上go即可不需要在定义是区分是否是异步函数调度器在合适的点进行切换,这个点是有很多
2023-06-20

Java并发编程面试题——JUC专题

文章目录 一、AQS高频问题1.1 AQS是什么?1.2 唤醒线程时,AQS为什么从后往前遍历?1.3 AQS为什么用双向链表,(为啥不用单向链表)?1.4 AQS为什么要有一个虚拟的head节点1.5 ReentrantLock的
2023-08-18

PHP面试题之选择题的示例分析

这篇文章主要介绍PHP面试题之选择题的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完! 1. 得到的输出是什么A.空 B.true C.false
2023-06-14

Java并发编程之线程状态实例分析

今天小编给大家分享一下Java并发编程之线程状态实例分析的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。线程状态概述线程由生到
2023-06-30

java二叉树面试题的示例分析

小编给大家分享一下java二叉树面试题的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!二叉树的深度题目:输入一颗二叉树的根节点,求该树的的深度。输入一颗二
2023-06-20

Java常量池面试题的示例分析

这篇文章主要介绍Java常量池面试题的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!今天My partner问我一个让他头疼的Java question,求输出结果:/** * * @author Dr
2023-06-17

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录