volatile有什么用处?
- 可以保证可见性,在多线程并发读写变量时。可以保证并发读写的可见性,但是不能保证原子性
- 可保证顺序性,多线程对变量进行并发读写时。使用volatile关键字修饰变量可以保证对变量读写的顺序性。
多线程并发读写变量会有什么问题?为什么?
1.计算机内存模型
因为cpu的运行速度远高于内存,所以如果cpu运算以内存为媒介的话会极大的浪费cpu的运算能力。为了解决这个问题,给cpu增加了多级高速缓存,cpu在进行计算是将变量从主内存读取到自己的高速缓存中,完成运算后再通过高速缓存将运算结果写会主内存。
这样做虽然解决了cpu资源浪费的问题,但是也带来了在不同的cpu中同一变量互相不可见(修改了不能被其他cpu感知到)的问题。
- 有什么解决办法吗?
1.cpu总线加锁机制。已经几乎没有用了。
2.缓存一致性协议(MESI)。
2.java内存模型
每个线程在操作变量时先将变量读取到线程的工作内存中,对变量操作结束后再将工作内存中的变量值写回主内存。如下图,这样就会存在和计算机内存模型一样的变量修改对不同的线程不可见的问题。
#### volatile是通过什么指令实现可见性和顺序性的?
- 通过lock前缀指令实现课件性和happen-before顺序性的。
- lock前缀指令可保证变量在执行assign操作后立刻执行store和write操作,同时其他线程工作内存中的该变量缓存是立刻到期。下次其他线程使用(读取)该变量的时候只能从工作内存中重新拉取修改后的值。从而保证了可见性。
- volatile修饰的变量在修改前后会添加写写内存屏障和读写内存屏障。从而保证指令的顺序性。
volatile为什么不能保证原子性?
因为变量在use后写会主内存的过程中,是不需要重新读取变量值的。所以无法阻止运算结果的覆盖也就没有办法保证原子性。也就是说在使用变量到给变量赋值之间有其他线程对变量进行了修改也不会让本次修改回滚,这就不能符合原子性的要求。