可见性与原子性
⑴可见性:一个线程对变量的修改,能够即使被其他线程"看到"
⑵原子性:不可再分的操作,即不能拆分成多步的操作。比如"a = 1;"和 "return a;"这样的操作都具有原子性。类似"a += b"这样的操作不具有原子性,
在 某些JVM中"a += b"可能要经过这样三个步骤:
① 取出a和b
② 计算a+b
③ 将计算结果写入内存
Synchronized:保证可见性和原子性
在Java内存模型中,Synchronized规定,线程在加锁时,先清空工作内存 -? 从主存中拷贝最新变量的副本到工作内存 -? 执行完代码 -? 将更改后的共享变量的值刷回到主存中 -? 释放互斥锁
Volatile:保证可见性,不保证操作原子性
Volatile实现内存可见性是通过store和load指令完成的;也就是对volatile变量执行写操作时,会在写操作后加入一条store指令,即强迫线程将最新的值刷新到主内存中;而在读操作时,会加入一条load指令,即强迫从主内存中读入变量的值。但volatile不保证volatile变量的原子性,例如:
1.volatile关键字不能保证操作原子性
2.保证内存可见性,即多个线程获取的数据是同一份
3.保证有序性,即被volatile声明的变量不会被编译器优化
4.保证happens-before
5.volatile只能作用于变量
volatile本质是在告诉JVM当前变量在寄存器中的值是不确定的,使用前,需要先从主存中读取,因此可以实现可见性。而对n=n+1,n++等操作时,volatile关键字将失效,不能起到像synchronized一样的线程同步(原子性)的效果。
1.保证重排序不会把后面的指令放到volatile声明变量前面,也不会把前面的放到后面
2.强制对缓存的修改操作立刻写入到主存
3.如果是写操作,会导致其他cpu中的缓存失效