| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> Java知识库 -> 掉了两根头发,可算是把volatile整明白了 -> 正文阅读 |
|
[Java知识库]掉了两根头发,可算是把volatile整明白了 |
volatile关键字可以说是Java虚拟机提供的最轻量级的同步机制,但对于为什么它只能保证可见性,不保证原子性,它又是如何禁用指令重排的,还有很多同学没彻底理解 相信我,坚持看完这篇文章,你将牢牢掌握一个Java核心知识点 先说它的两个作用:
每个字都认识,凑在一起就麻了 这两个作用通常很不容易被我们Java开发人员正确、完整地理解,以至于许多同学不能正确地使用volatile 关于可见性不多bb,码来
代码很好理解,开了十个线程对同一个共享变量count做累加,每个线程累加1w次 count我们已经用volatile修饰,已经保证了count对十个线程在内存中的可见性,按理说十个线程执行完毕count的值应该10w 然鹅,运行多次,结果都远小于期望值 你肯定听过一句话:volatile只保证可见性,不保证原子性 这句话就是答案,但是依旧很多人没搞懂其中的奥秘 说来话长我长话短说,简单来讲就是 count++这个操作不是原子的,它是分三步进行
要彻底搞懂这个问题,我们得从字节码入手 下面是increase方法编译后的字节码
ICONST_1和IADD其实就是真正的++操作 关键点来了,volatile只能保证线程在GETSTATIC这一步拿到的值是最新的,但当该线程执行到下面几行指令时,这期间可能就有其它线程把count的值修改了,最终导致旧值把真正的新值覆盖 懂我意思吗 所以,并发编程中,只靠volatile修饰共享变量是不可靠的,最终还是要通过对关键方法加锁来保证线程安全 就如上面的demo,稍加修改就能实现真正的线程安全 最简单的,给increase方法加个synchronized (synchronized怎么实现线程安全的我就不啰嗦了,我以前讲过 synchronized底层实现原理)
run几下 到现在,对于以下两点你应该有了新的认知
关于指令重排并发编程中,cpu自身和虚拟机为了提高执行效率,都会采用指令重排(在保证不影响结果的前提下,将某些代码乱序执行)
指令重排在大部分场景下确实能提升执行效率,但有些场景对代码执行顺序是强依赖的,此时我们需要禁用指令重排,如下面这个场景 其描述的场景是开发中常见配置读取过程,只是我们在处理配置文件时一般不会出现并发,所以没有察觉这会有问题。 禁用指令重排只需要将变量声明为volatile,是不是很神奇 我们来看看volatile是如何实现禁用指令重排的 也借用《深入理解Java虚拟机》的一个例子吧,比较好理解 最后,留一个能加深大家对volatile理解的问题,兄弟们好好思考下:
ok我话说完 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 9:56:58- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |