volatile特性
volatile的特性:
1. 保证可见性
2. 不保证原子性
3. 禁止指令重排
- 可见性
可见性:线程变量可以同步主存的共享变量
可见性问题:线程和cpu不是在同一内存中工作,cpu的内存叫做主存,线程的内存叫做工作内存。当线程中某个变量发生了变化,就会同步到主存中,没有变化的就不会同步。可以发现有个缺陷,当线程A和线程B同时调用同一个变量,线程A中没有对这个变量进行操作,而线程B对这个变量进行了操作,并且同步到了主存中。此时会发生一个问题,就是线程A不知道该变量已经被修改。这就产生了可见性问题。
package com.luoKing.Dvolatile; import java.util.concurrent.TimeUnit; public class seeyou { static int num = 0; public static void main(String[] args) throws InterruptedException { new Thread(()->{ while (num==0){ } }).start(); TimeUnit.SECONDS.sleep(1); num++; System.out.println(num); } }
我们可以发现程序发生阻塞。
如何解决这个问题呢?
num用volatile修饰,因为volatile可以保证可见性
package com.luoKing.Dvolatile; import java.util.concurrent.TimeUnit; public class seeyou { static volatile int num = 0; public static void main(String[] args) throws InterruptedException { new Thread(()->{ while (num==0){ } }).start(); TimeUnit.SECONDS.sleep(1); num++; System.out.println(num); } }
2.不保证原子性
什么是原子性?
原子,组成物质的最小单位,不可再分。原子性操作:不可中断,要么全部执行成功,要么全部执行失败。不能被其他线程干扰。
package com.luoKing.Dvolatile; public class unatomic { private volatile static int num; public static int add(){ return num++; } public static void main(String[] args) { for (int i = 1; i <= 10; i++) { new Thread(() -> { for (int i1 = 0; i1 < 2000; i1++) { add(); } }).start(); } while (Thread.activeCount()>2){//mian线程和gc线程在有其他线程运行的时候,礼让线程,不执行 Thread.yield(); } System.out.println("num = " + num); } }
结果
num = 17188
可见volatile并不可以保证原子性
- 禁止指令重排
指令重排:我们写的程序,在计算机中执行,并不是按照我们程序的顺序执行,他会重写编排,以达到的最优的性能,但这也会导致运行的结果和我们期望的结果有偏差
加了volatile关键字,在cpu中会产生一个叫做内存屏障的东西,会阻止指令重排
作用:
- 保证程序按照特定的顺序操作
- 可以保证某些变量的内存可见性
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决