volidate是多线程环境下,可以保证不同的线程之间,操作同一个变量能互相通讯可见的。但是不能保证操作原子性。
volidate是如何保证内存可见性的/有序性,防止指令重排序?
主要是内存屏障,通过添加指令保证
可见性
1.通过指令。lock前缀指令。在由volidate修饰的变量,前后会加上lock指令,在计算操作完变量后,会强制变量直接协会主内存。
然后,通过协议嗅探机制线程的工作内存,通知其他的线程从主内存读取数据。
volidate修饰的变量,会在程序执行前后添加一个汇编指令,这个指令会促发相应的协议,这个协议会促发通过嗅探技术让总线不同的监控变量值的变化,,一旦变化,会直接从主内存写回工作内存。
有序性
内存屏障指令,load,loadstore等指令 loadBarrier 读屏障 ,storeBarrier写屏障。在前后代码加上这些指令,可以保证代码执行指令不进行重排序。
cpu和内存交互
cpu缓存
内存读取的速度,赶不上cpu的速度,所以在cpu上加了高速缓存。
但是这样就有了缓存一致性的问题?每个cpu都有自己的高速缓存区。这样对于涉及一块主内存区域的操作的时候,怎么保证各个缓存区的数据一致性,
有缓存,就会有一致性问题
为了解决这个问题,各个cpu需要遵循一致性协议MSI,MESI
在cpu层面,提供了一系列的保障
1.硬件层内存屏障 loadBarrier 读屏障 ,storeBarrier写屏障
不同硬件处理器的内存屏障方式不一样,java怎么屏蔽这些差异的:通过jvm生成内存屏障指令。
读指令;在其他指令前插入读指令,会直接读取主内存的数据,使得高速缓存区失效 volidate就是这样的。在读写前后添加内存屏障,实现内存可见性
内存屏障的作用:强制从主内存读取数据,使得脏数据被刷新,重写写回主内存,
阻止内存屏障两侧指令重排序
编写并发程序,主要是对于共享变量的管理
什么是同步:
同步不仅是原子操作,临界。更是内存可见性的。一个线程同步操作完,希望操作后的信息,被其他线程看到。
什么是重排序
重排序:会导致写入变量的顺序和代码的顺序不一致。在多线程环境里面。不能保证,按照程序写定的顺序执行
volidate修饰,可以使变量的值,在一个线程更新时,其他线程可以预见,不会重排序。这个变量会被监视是共享的
volidate的使用:
在一个引用的状态需要可见,或则标志重要的生命周期事件(初始化和销毁。)检查状态的标记:循环
volidatae只能保证可见性,不能保证原子性。 加锁:既可以保证原子性和可见性。 对于变量修改用volidate不能达到数据同步安全
使用volidate条件:
当只有一个线程修改变量操作,
写入的变量不依赖其他线程的变量值
变量不需要和其他需要变更状态的变量之间有依赖。
访问变量时,没有其他原因加锁