面试官:volatile能不能不保证原子性?如何解决呢?

2023-10-09 00:18

本文主要是介绍面试官:volatile能不能不保证原子性?如何解决呢?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

volatile不保证原子性

大厂面试题:

  • 请你谈谈对volatile的理解?

  • CAS你知道吗?

  • 原子类AtomicInteger的ABA问题谈谈?原子更新引用知道吗?

  • 我们都知道ArrayList是线程不安全的,请编码写一个不安全的案例并给出解决方案?

  • 公平锁/非公平锁/可重入锁/递归锁/自旋锁谈谈你的理解?请手写一个自旋锁。

  • CountDownLatch、CyclicBarrier、Semaphore使用过吗?

  • 阻塞队列知道吗?

  • 线程池用过吗?ThreadPoolExecutor谈谈你的理解?

  • 线程池用过吗?生产上你是如何设置合理参数?

  • 死锁编码及定位分析?

解析:

  • volatile为什么不保证原子性?

  • 请你使用代码验证volatile不保证原子性?

  • 有什么办法让volatile保证原子性?

1、volatile不保证原子性代码验证

public class VolatileAtomDemo {undefined// volatile不保证原子性// 原子性:保证数据一致性、完整性volatile int number = 0;public void addPlusPlus() {undefinednumber++;}public static void main(String[] args) {undefinedVolatileAtomDemo volatileAtomDemo = new VolatileAtomDemo();for (int j = 0; j < 20; j++) {new Thread(() -> {for (int i = 0; i < 1000; i++) {volatileAtomDemo.addPlusPlus();}}, String.valueOf(j)).start();}// 后台默认两个线程:一个是main线程,一个是gc线程while (Thread.activeCount() > 2) {undefinedThread.yield();}// 如果volatile保证原子性的话,最终的结果应该是20000// 但是每次程序执行结果都不等于20000System.out.println(Thread.currentThread().getName() + "\tfinal number result = " + volatileAtomDemo.number);}
}

代码执行结果如下:多次执行结果证明volatile不保证原子性

2f9a42ed73db05c847f26d0986362a71.png d10712fdad2fdb0e2fba68b9732f3937.png

2、volatile不保证原子性原理分析

number++操作对应的字节码:

181db13b773d47c6a4fd4823feb5dab2.png

number++被拆分成3个指令

  • 执行GETFIELD拿到主内存中的原始值number

  • 执行IADD进行加1操作

  • 执行PUTFIELD把工作内存中的值写回主内存中

当多个线程并发执行PUTFIELD指令的时候,会出现写回主内存覆盖问题,所以才会导致最终结果不为20000,volatile不能保证原子性。

dbe290417351b896f5eee313c271de55.png

3、解决volatile不保证原子性问题

(1)方法前加synchronized解决

public synchronized void  addPlusPlus() {number++;
}

(2)加锁解决

// 使用锁保证数据原子性
Lock lock = new ReentrantLock();
public void addPlusPlus() {undefinedlock.lock();number++;lock.unlock();
}

(3)原子类解决

// 使用原子类保证数据原子性
public class VolatileSolveAtomDemo {// 原子Integer类型,保证原子性private AtomicInteger atomicNumber = new AtomicInteger();// 底层通过CAS保证原子性public void addPlusPlus() {undefinedatomicNumber.getAndIncrement();}public static void main(String[] args) {VolatileSolveAtomDemo volatileSolveAtomDemo = new VolatileSolveAtomDemo();for (int j = 0; j < 20; j++) {undefinednew Thread(() -> {undefinedfor (int i = 0; i < 1000; i++) {undefinedvolatileSolveAtomDemo.addPlusPlus();}}, String.valueOf(j)).start();}// 后台默认两个线程:一个是main线程,一个是gc线程while (Thread.activeCount() > 2) {Thread.yield();}// 因为volatile不保证原子性,所以选择原子类AtomicInteger来解决volatile不保证原子性问题// 最终每次程序执行结果都等于20000System.out.println(Thread.currentThread().getName() + "\tfinal number result = " + volatileSolveAtomDemo.atomicNumber.get());}
}

代码执行结果如下:多次执行结果证明原子类是可以解决volatile不保证原子性问题

91ab8107197d6ebc8792aa7be8caf334.png

来源:https://www.sixstaredu.com/

e3b6544b577cdeadfc8ab92e90239c94.png

这篇关于面试官:volatile能不能不保证原子性?如何解决呢?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/168961

相关文章

2024.6.24 IDEA中文乱码问题(服务器 控制台 TOMcat)实测已解决

1.问题产生原因: 1.文件编码不一致:如果文件的编码方式与IDEA设置的编码方式不一致,就会产生乱码。确保文件和IDEA使用相同的编码,通常是UTF-8。2.IDEA设置问题:检查IDEA的全局编码设置和项目编码设置是否正确。3.终端或控制台编码问题:如果你在终端或控制台看到乱码,可能是终端的编码设置问题。确保终端使用的是支持你的文件的编码方式。 2.解决方案: 1.File -> S

vue同页面多路由懒加载-及可能存在问题的解决方式

先上图,再解释 图一是多路由页面,图二是路由文件。从图一可以看出每个router-view对应的name都不一样。从图二可以看出层路由对应的组件加载方式要跟图一中的name相对应,并且图二的路由层在跟图一对应的页面中要加上components层,多一个s结尾,里面的的方法名就是图一路由的name值,里面还可以照样用懒加载的方式。 页面上其他的路由在路由文件中也跟图二是一样的写法。 附送可能存在

vue+elementui分页输入框回车与页面中@keyup.enter事件冲突解决

解决这个问题的思路只要判断事件源是哪个就好。el分页的回车触发事件是在按下时,抬起并不会再触发。而keyup.enter事件是在抬起时触发。 so,找不到分页的回车事件那就拿keyup.enter事件搞事情。只要判断这个抬起事件的$event中的锚点样式判断不等于分页特有的样式就可以了 @keyup.enter="allKeyup($event)" //页面上的//js中allKeyup(e

vue+elementui--$message提示框被dialog遮罩层挡住问题解决

最近碰到一个先执行this.$message提示内容,然后接着弹出dialog带遮罩层弹框。那么问题来了,message提示框会默认被dialog遮罩层挡住,现在就是要解决这个问题。 由于都是弹框,问题肯定是出在z-index比重问题。由于用$message方式是写在js中而不是写在html中所以不是很好直接去改样式。 不过好在message组件中提供了customClass 属性,我们可以利用

Pycharm配置conda环境(解决新版本无法识别可执行文件问题)

引言: 很多小伙伴在下载最新版本的pycharm或者更新到最新版本后为项目配置conda环境的时候,发现文件夹目录中无法显示可执行文件(一般为python.exe),以下就是本人遇到该问题后试验和解决该问题的一些方法和思路。 一般遇到该问题的人群有两种,一种是刚入门对pycharm进行conda环境配置的小白(例如我),不熟悉相关环境配置的操作和过程,还有一种是入坑pycharm有段时间的老手

青龙面板之Ninja无法安装无法拉库问题解决

因为之前的Ninja库已经不能用了,甚至新找到的库也不能用了,好尴尬,这里使用线下版本进行安装。 ninja安装新方法,其是方法还是原来的,只不过Ninja的库原作者删了,没法直接git了,但是我找到了源码包,我们可以直接通过宝塔面板拖进去。 源码包地址: https://download.csdn.net/download/u012134073/24813485 备用地址: 链接: h

华为某员工爆料:偷偷跑出去面试,被面试官鄙视了。第一句话就问:华为淘汰的吧,35岁了,这个年龄在华为能混得下去吗?身体没啥毛病吧

“你都35岁了,难不成是被华为淘汰的?在华为混不下去了吧?身体没啥毛病吧,我们这体检可是很严的。” 近日,一位华为员工在朋友圈爆料,自己在面试时遭到了面试官的无理取闹和人身攻击,原因仅仅是因为他35岁了,曾经在华为工作过。 这番话,充满了傲慢与偏见,让人听了义愤填膺。这位面试官的言行,不仅是对求职者的不尊重,更是对职场规则的践踏。 面试本应是双向选择的过程,企业和求职者在相互了解的基

tomcat端口被占用如何解决

转载:https://www.cnblogs.com/demon09/p/9248445.html

# bash: chkconfig: command not found 解决方法

bash: chkconfig: command not found 解决方法 一、chkconfig 错误描述: 这个错误表明在 Bash 环境下,尝试执行 chkconfig 命令,但是系统找不到这个命令。chkconfig 命令是一个用于管理 Linux 系统中服务的启动和停止的工具,通常它是 initscripts 包的一部分,但在最新的 Linux 发行版中可能已经被 syste

@ControllerAdvice:你可以没用过,但是不能不了解

1.概述 最近在梳理Spring MVC相关扩展点时发现了@ControllerAdvice这个注解,用于定义全局的异常处理、数据绑定、数据预处理等功能。通过使用 @ControllerAdvice,可以将一些与控制器相关的通用逻辑提取到单独的类中进行集中管理,从而减少代码重复,提升代码的可维护性。 定义如下 /*** Specialization of {@link Component @