一、volatile
- 1.volatile的底层原理是内存屏障,Memory Barrier, Memory Fence
- 2.对volatile变量的写指令(赋值操作)后会加入写屏障
- 3.对volatile变量的读指令(取变量值)前会加入读屏障
- 4.写屏障的作用会将写屏障之前的赋值改动操作,对共享变量的改动都同步到主内存中
- 5.读屏障的作用会将读屏障之后的对共享变量的读取,加载的是主存中最新的数据
- 6.写屏障的作用会确保指令重排序时,不会将写屏障之前的代码排在写屏障之后
- 7.读屏障的作用会确保指令重排序时,不会将读屏障之后的代码排在读屏障之前
- 8.不能解决指令交错,写屏障仅仅是保证之后的读能够读到最新的结果,不能保证另个线程b在线程a写之前读,然后在线程a写之后,线程b再写
- 9.有序性的保证只保证了本线程内相关代码不被重新排序
- 10.jdk1.5之后才能生效
二、保证可见性
- 1.写屏障(sfence)保证在该屏障之前的,对共享变量的改动,都同步到主存之中
- 2.volatile a变量,当a变量被赋值后,a=1后会加入一个写屏障,会将a=1赋值操作之前的对共享变量的改动都同步到主存中
- 3.读屏障(lfence)保证在该屏障之后,对共享变量的读取,加载的是主存中最新数据
- 4.volatile a变量,当if(a==2)时,读取a变量前会加一个读屏障,在读屏障之后对共享变量的读取加载的都是主存中最新的数据
三、保证有序性
- 1.写屏障会确保指令重排时,不会将写屏障之前的代码排在写屏障之后,例如int a = 2;boolean b = true; 假如b是被volatile关键字修饰,则给b赋值为true之后,会产生一个写屏障,那么写屏障之前的操作 a=2的赋值操作不会重排到写屏障之后,也就是保证了a=2赋值操作在b=true的赋值操作之前
- 2.读屏障会确保指令重排时,不会将读屏障之后的代码排在读屏障之前,例如if(b); int a = 2; 假如b是被volatile关键字修饰,则读取b变量时,会给b变量读操作前加一个读屏障,在读屏障之后的代码a=2,不会重排在读屏障之前,因此保证a=2操作在if(b)读b变量之后
四、不能解决指令交错
- 1.线程a和线程b,修改volatile关键字修饰的变量i
- 2.线程a对变量i进行自加1操作,线程b对变量i进行自减1操作
- 3.开始线程a读取变量i为0,线程b读取变量i为0
- 4.线程a自加1成功,并将i=1写回主存,线程b自减成功,并将i=-1写回主存
- 5.此时主存中变量i的值为-1,正常来说结果应该是0
- 6.且在线程a、b各自的线程内,都能保证各自的指令有序,不能重排序
- 7.因此volatile关键字修饰的变量没有解决指令交错带来的线程安全问题
- 8.线程a、线程b之间的指令会有一定的交错,volatile不能保证原子性
- 9.synchronized可以保证可见性、有序性和原子性(共享变量要完全在synchronized代码块内,如果代码块外部还有变量的使用,则不能保证指令不重排)
文章来源地址https://www.toymoban.com/news/detail-462703.html
文章来源:https://www.toymoban.com/news/detail-462703.html
到了这里,关于【多线程】volatile关键字的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!