volatile特性

volatile的特性:

1. 保证可见性
2. 不保证原子性
3. 禁止指令重排

  1. 可见性

可见性:线程变量可以同步主存的共享变量

可见性问题:线程和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并不可以保证原子性

  1. 禁止指令重排

指令重排:我们写的程序,在计算机中执行,并不是按照我们程序的顺序执行,他会重写编排,以达到的最优的性能,但这也会导致运行的结果和我们期望的结果有偏差

加了volatile关键字,在cpu中会产生一个叫做内存屏障的东西,会阻止指令重排
作用:

  1. 保证程序按照特定的顺序操作
  2. 可以保证某些变量的内存可见性
posted @   小罗要有出息  阅读(64)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决
点击右上角即可分享
微信分享提示