上次我们学习了volatile是如何解决多线程环境下共享变量的内存可见性问题,并且简单介绍了基于多核CPU并发缓存架构模型的Java内存模型。
详情见文章:
volatile很难?由浅入深怼到CPU汇编,彻底搞清楚它的底层原理
在并发编程中,有三个重要的特性:
- 内存可见性
- 原子性
- 有序性
volatile解决了并发编程中的可见性和有序性,解决不了原子性的问题,原子性的问题需要依赖synchronized关键字来解决。
关于并发编程三大特性的详细介绍,大家可以点击下方卡片搜索查看:
内存可见性在上一篇文章中已经验证,本文我们继续通过代码学习如下内容:1、volatile为什么解决不了原子性问题?2、缓存行、缓存行填充3、CPU优化导致的乱序执行4、经典面试题:DCL必须要有volatile关键字吗?5、valatile关键字是如何禁止指令重排序的?
以上每一步都会有一段代码来验证,话不多说,开始输出干货!
1、volatile为什么解决不了原子性问题?
如果你对volatile了解的还可以,那么咱们继续往下看,如果不是太熟悉,请先行阅读上一篇文章。
老规矩,先来一段代码:
这段代码的输出结果是多少?10000?大于10000?小于10000?
程序执行10次输出的结果如下:
join:10000
join:10000
join:10000
join:9819
join:10000
join:10000
join:10000
join:9898
join:10000
join:10000
会有小几率的出现小于10000的情况,因此volatile是无法保证原子性的,那么到底在什么地方出问题了呢?
还是用上篇文章的图来说明一下程序的整体流程: