参考:
https://www.cnblogs.com/dolphin0520/p/3920373.html
https://www.jianshu.com/p/157279e6efdb
https://blog.csdn.net/ThinkWon/article/details/102243670
https://www.jianshu.com/p/3893fb35240f
https://zhuanlan.zhihu.com/p/138819184
https://cloud.tencent.com/developer/information/volatile%E5%85%B3%E9%94%AE%E5%AD%97%E8%AF%A6%E8%A7%A3
https://www.jb51.net/article/197078.htm
https://www.yisu.com/zixun/197907.html
https://www.zhihu.com/question/329746124
含义:
volatile是并发编程中的一个关键字,只能修饰变量,无法修饰方法及代码块等,
多线程访问volatile不会发生阻塞,效率比synchronized高,而synchronized会出现阻塞。
volatile能保证数据的可见性,但不能保证原子性
volatile 作用:
1- 保证变量的内存可见性(不保证原子性)
volatile 用于将变量标记为“存储于主内存中”。更确切地说,对 volatile 变量的每次读操作都会直接从计算机的主存中读取,
而不是从 cpu 缓存中读取;同样,每次对 volatile 变量的写操作都会直接写入到主存中,而不仅仅写入到 cpu 缓存里。当然代价也比较高
2- 禁止指令重排序
volatile关键字禁止指令重排序有两层意思:
1)当程序执行到volatile变量的读操作或者写操作时,在其前面的操作的更改肯定全部已经进行,且结果已经对后面的操作可见;在其后面的操作肯定还没有进行;
2)在进行指令优化时,不能将在对volatile变量访问的语句放在其后面执行,也不能把volatile变量后面的语句放到其前面执行。
原理:
下面这段话摘自《深入理解Java虚拟机》:
“观察加入volatile关键字和没有加入volatile关键字时所生成的汇编代码发现,加入volatile关键字时,会多出一个lock前缀指令”
lock前缀指令实际上相当于一个内存屏障(也成内存栅栏),内存屏障会提供3个功能:
1)它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成;
2)它会强制将对缓存的修改操作立即写入主存;
3)如果是写操作,它会导致其他CPU中对应的缓存行无效。
问题:
volatile和static的区别
volatile:声明变量的一致性(工作内存和主内存数值保持一致)
static:声明变量的唯一性(各个线程可能具有本地缓存的值)
i++是不是线程安全?为什么?Java有哪些办法让i++变成线程安全?
不是,i++的执行分为 读取.赋值.回写,没办法保证原子性,所以不是线程安全的
线程安全可以采用,synchronized加锁,Lock加锁,或者采用JUC包下的AtomicInteger