网站首页 > 文章精选 正文
volatile 是 Java 中的一个关键字,用于修饰变量,主要解决多线程环境下的内存可见性问题和指令重排序问题。
主要作用
- 保证可见性:当一个线程修改了 volatile 变量的值,新值会立即被刷新到主内存中,其他线程读取时会直接从主内存读取最新值。
- 禁止指令重排序:防止 JVM 对 volatile 变量相关的代码进行指令重排序优化。
基本用法
public class SharedObject {
public volatile int counter = 0;
}
volatile 的特性
1. 内存可见性保证
没有 volatile 修饰时可能出现的问题:
// 没有 volatile 修饰
boolean running = true;
void work() {
while(running) {
// 工作代码
}
}
void stop() {
running = false;
}
在这个例子中, stop() 方法修改 running 的值后, work() 方法的循环可能不会立即停止,因为工作线程可能在自己的工作内存中保留了 running 的旧值。
使用 volatile 可以解决:
volatile boolean running = true;
2. 禁止指令重排序
volatile 通过插入内存屏障来防止指令重排序,这在单例模式的双重检查锁定中很重要:
class Singleton {
private static volatile Singleton instance;
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
如果不使用 volatile, instance = new Singleton() 可能会被重排序,导致其他线程看到未完全初始化的对象。
volatile 的局限性
1. 不保证原子性:volatile 不能替代 synchronized,它不保证复合操作的原子性。
错误示例:
volatile int count = 0;
count++; // 这不是原子操作
count++ 实际上是读-改-写三个操作,volatile 不能保证这三个操作的整体原子性。
2. 不适用于依赖当前值的操作:如 count = count + 1 或 count++
volatile 适用场景
- 状态标志位(如前面示例中的 running )
- 单次安全发布(如单例模式的双重检查锁定)
- 独立观察(定期发布观察结果供程序使用)
- "开销较低的读-写锁策略"(读远多于写的情况)
volatile 与 synchronized 比较
特性 | volatile | synchronized |
作用范围 | 变量 | 变量、代码块、方法 |
内存可见性 | 保证 | 保证 |
原子性 | 不保证 | 保证 |
阻塞 | 不会导致线程阻塞 | 可能导致线程阻塞 |
性能 | 更高 | 相对较低 |
底层原理
volatile 的实现依赖于 JVM 的内存屏障:
- 写操作前插入 StoreStore 屏障
- 写操作后插入 StoreLoad 屏障
- 读操作前插入 LoadLoad 屏障
- 读操作后插入 LoadStore 屏障
这些屏障保证了 volatile 变量的读写操作不会被重排序,并且写操作后会立即刷新到主内存。
猜你喜欢
- 2025-06-28 java 9新特性 模块化系统(java新版本新特性)
- 2025-06-28 JAVA大集群下的负载均衡之道(java负载均衡是什么意思)
- 2025-06-28 Java Lambda表达式详解(java的lambada表达式)
- 2025-06-28 java ArrayList类详解及Vector类简介
- 2025-06-28 Java对比学习Pyton之高级特性:函数式编程
- 2025-06-28 Java面试必备八股文(java面试必备八股文案例)
- 2025-06-28 仓颉、Java、Golang性能测试——数组扩容
- 2025-06-28 怎么求第K大的数,topK 问题(快排的应用)java
- 2025-06-28 轻松掌握 Java 变量:编程世界的存储小能手
- 2025-06-28 java采用int32作为hashcode,会不会出现更高的碰撞概率?
- 最近发表
- 标签列表
-
- newcoder (56)
- 字符串的长度是指 (45)
- drawcontours()参数说明 (60)
- unsignedshortint (59)
- postman并发请求 (47)
- python列表删除 (50)
- 左程云什么水平 (56)
- 计算机网络的拓扑结构是指() (45)
- 编程题 (64)
- postgresql默认端口 (66)
- 数据库的概念模型独立于 (48)
- 产生系统死锁的原因可能是由于 (51)
- 数据库中只存放视图的 (62)
- 在vi中退出不保存的命令是 (53)
- 哪个命令可以将普通用户转换成超级用户 (49)
- noscript标签的作用 (48)
- 联合利华网申 (49)
- swagger和postman (46)
- 结构化程序设计主要强调 (53)
- 172.1 (57)
- apipostwebsocket (47)
- 唯品会后台 (61)
- 简历助手 (56)
- offshow (61)
- mysql数据库面试题 (57)