一、可见性
是指多线程在不同cpu缓存(多核)中对同一个变量进行修改,导致的不可见
二、原子性
指线程间切换导致的原子性问题
一条编程语句执行往往包含多条CPU指令,操作系统做任务切换,可以发生在任意一条cpu指令执行完
比如count+=1;这条语句包含3条cpu指令:
1.把变量count从内存中加载到cpu寄存器;
2.在cpu寄存器中执行+1操作
3.把结果写入内存(也可能是因为缓存机制写入的是cpu缓存而不是内存)
三、有序性
因为编译器优化导致程序语句的执行顺序发生变化。
经典案例就是单例模式中利用双重检查创建单例对象。
1 public class Singleton{
3 private static Singleton instance; 4 5 private static Singleton getInstance(){ 6 7 if(instance==null){ 8 9 sychronized(Singleton.class){ 10 11 if(instance==null){ 12 13 instance=new Singleton(); 14 15 } 16 17 } 18 19 } 20 21 return instance; 22 23 } 24 25 }
问题出在new操作上,我们以为的操作是这样的:
1.分配一块内存M;
2.在内存M上初始化Singleton对象
3.将地址M赋值给变量instance
而实际上经过编译优化的执行操作是这样的:
1.分配一块内存M;
2.将地址M赋值给变量instance
3.在内存M上初始化Singleton对象
解决办法:把属性Singleton instance加修饰符volatile就完美了,对instance进行volatile语义声明,就可以禁止指令重排序。
四、关于volatile资料参考:https://www.jianshu.com/p/ccfe24b63d87
volatile 是一个类型修饰符。volatile 的作用是作为指令关键字,确保本条指令不会因编译器的优化而省略。
volatile 的特性
保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。(实现可见性)
禁止进行指令重排序。(实现有序性)
volatile 只能保证对单次读/写的原子性。i++ 这种操作不能保证原子性。
五、关于cpu缓存、线程工作内存:https://blog.csdn.net/u013851082/article/details/70314778/