一、并发编程特性
1、原子性:一个操作要么成功要么失败,中间不会中断
2、可见性:多个线程同时访问某个变量,当变量发生修改,其他线程可以立即看到被修改的值
3、有序性:代码按照代码的先后顺序执行
二、volatile可见性原理
volatile保证了可见性和有序性,可以有效的防止指令重排;
导致程序可见性问题,主要是因为当线程工作时,需要先把主内存中的变量拷贝(Load)到工作内存中,执行完成后,再写回(Store)到主内存中;所以这个中间就会存在多线程复写的问题;
当加了volatile关键字,则通过"内存屏障"来防止指令重排;
1. lfence,是一种Load Barrier 读屏障
2. sfence, 是一种Store Barrier 写屏障
3. mfence, 是一种全能型的屏障,具备ifence和sfence的能力
4. Lock前缀,Lock不是一种内存屏障,但是它能完成类似内存屏障的功能。Lock会对CPU总线和高速缓存加锁,可以理解为CPU指令级的一种锁。它后面可以跟ADD, ADC, AND, BTC, BTR, BTS, CMPXCHG, CMPXCH8B, DEC, INC, NEG, NOT, OR, SBB, SUB, XOR, XADD, and XCHG等指令。
JVM提供的内存屏障:LoadLoad,StoreStore,LoadStore,StoreLoad;
可见性主要是通过MESI(修改 Modified 独享 Exclusive 共享Shared 无效 Invalid)机制来保证可见性;通过字节码可以看到,被volatile修饰的变量会有ACC_VOLATILE访问标识,通过汇编可以看到,执行时会lock
不同的硬件架构对MESI的实现不一样,一般CPU的三级缓存架构,读取缓存行(64byte)到cpu缓存,然后该CPU通过bus总线监控是否还有其他CPU读取该变量,通知也是通过总线通知;如果同时有其他线程对该变量进行修改,则会进行总线裁决;