并发过程中volatile能否保证线程安全( 二 )
我们来看一个典型的例子 , 伪代码如下 。 执行完所有线程任务 , 我们期望的结果会是30*10000 。 但实际却是一个小于30*10000的数 , 刚开始看到一定觉得有点奇怪 , 但仔细一想就清楚了 。 count++;编译后最终并非一个原子操作 , 它由几个指令一起组合实现 。 在Java内存模型中 , count++;被分割成多个步骤 , 这几步不具有原子性 。 假如在完成的过程中 , 其他线程就去读了主存的count变量 , 那明显将导致脏读现象 。
文章插图
例子
volatile无锁导致这个问题的原因其实是因为volatile不具备锁操作 , 要解决此问题其实不难 , 就是将这这些操作变为原子操作 。 即保证线程一完成之前不能有其他线程读取count变量 , 要达到目的只需对count变量加一个互斥锁即可 。 线程一执行前对count加锁 , 其他线程无法对count进行访问 。 线程一执行完后释放锁 , 此刻开始才允许其他线程获取此变量 。
总结Volatile是一个很容易搞混的关键词 , 很多经验丰富的开发人员都不能正确使用它 。 本节从机器结构讲到对应的Java内存模型 , 再引出主存与工作内存之间数据同步的问题 。 进而更好地解释了volatile的确切含义 , 它只保证可见性 , 它不足以保证数据的同步性 。
volatile、可见性的底层实现是通过内存屏障实现的 。 内存屏障的另一个作用就是强制刷出各种CPU缓存数据 , 因此任何CPU上的线程都可以读取到这些数据的最新版本 。
更多Java并发原理可关注作者下面的专栏:
作者简介:笔名seaboat , 擅长人工智能、计算机科学、数学原理、基础算法 。 出版书籍:图解数据结构与算法、Tomcat内核设计剖析、图解Java并发原理、人工智能原理科普 。
推荐阅读
- Redis集群做法的难点,百万并发客户端「实战」
- 为什么 Redis 单线程能支撑高并发?
- 针对智能城市建设过程中的三大痛点,京东数科如何解决?
- “天线宝宝”这样“举高高”
- 解决 idea 使用过程中让你觉得不爽的一些问题
- Java并发编程-线程基础
- 掌握这些高并发面试题,保证你能造火箭拿offer
- 具有Java基础,在自学Python的过程中需要注意哪些内容
- 从零手写并发框架(四)异步转同步 springboot 整合
- 并发控制工具相位器Phaser实现原理