volatile关键字介绍-Java

volatile 是 Java 中用于修饰变量的关键字,常用于多线程编程。它是一个轻量级的同步机制,用来确保共享变量在多个线程之间的可见性,并防止指令重排序。

1. volatile 的特性

volatile 修饰的变量具备以下两个关键特性:

1.可见性(Visibility):

  • 当一个线程修改了 volatile 修饰的变量,修改后的值会立刻被刷新到主内存。
  • 其他线程读取这个变量时,会直接从主内存中读取最新值,而不是从线程的工作内存中读取旧值。效果:所有线程对 volatile 变量的访问是最新的。

2.禁止指令重排序(Orderliness):

  • 在 volatile 变量的读写操作前后,编译器和处理器不会对代码进行重排序。
  • 效果:确保对 volatile 变量的操作顺序符合程序的逻辑预期。

2. volatile 的实现原理

(1) 内存可见性原理

  • Java 内存模型(JMM)
  • Java 使用主内存(Main Memory)和线程工作内存(Working Memory)来管理共享变量。
  • 通常,线程会将共享变量从主内存拷贝到自己的工作内存中,进行操作后再写回主内存。
  • volatile 保证变量的修改会立即刷新到主内存,同时禁止线程从工作内存中读取过期数据。

(2) 指令重排序规则

  • 编译器和 CPU 在执行程序时,可能会出于性能优化对指令进行重排序。
  • 使用 volatile 修饰变量后,读写操作会添加内存屏障(Memory Barrier),防止指令重排序。
  • 内存屏障是一种 CPU 指令,确保屏障前的所有操作在屏障之后的操作之前完成。

3. volatile 的使用场景

(1) 状态标志变量

volatile 常用于表示线程间的状态,例如停止标志。

public class VolatileFlag {
    private volatile boolean running = true;

    public void stop() {
        running = false; // 修改 running 状态
    }

    public void execute() {
        while (running) {
            // 执行任务
        }
    }
}
  • 这里的 volatile 保证了 running 对所有线程的可见性。

(2) 单例模式的双重检查锁

volatile 可用于确保双重检查锁的线程安全。

public class Singleton {
    private static volatile Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
  • 这里的 volatile 防止实例化过程中指令重排序导致的线程安全问题。

(3) 配合非阻塞算法volatile 可以在某些非阻塞算法中保证共享变量的可见性。例如,计数器递增:

public class Counter {
    private volatile int count = 0;

    public void increment() {
        count++;
    }
}

注意count++ 不是原子操作,此处仅展示可见性。如果需要原子性,需使用 AtomicInteger

4. volatile 的局限性

  1. 不保证原子性:volatile 只能保证变量的可见性,不能保证操作的原子性。
  2. 仅适用于单个变量:volatile 只能保证单个变量的可见性,对于复合操作(如 i++)或多个变量的操作不提供安全性。
  3. 性能开销:使用 volatile 会降低一定的性能,因为它需要频繁地刷新主内存,导致缓存失效。

5. volatile 与 synchronized 的对比

特性

volatile

synchronized

功能

仅保证可见性,不能保证原子性

同时保证可见性和原子性

锁机制

无锁机制,适合轻量级操作

内置锁,适合复杂的线程同步

性能

性能较高,适合简单场景

性能较低(JDK 1.6 以后优化性能较好)

适用场景

状态标志、双重检查锁

复杂的线程同步场景

是否阻塞线程

非阻塞

阻塞线程

6. volatile 与 Atomic 的对比

特性

volatile

Atomic 类

功能

仅保证可见性,不能保证原子性

保证可见性和原子性

实现原理

使用内存屏障(Memory Barrier)

使用 CAS(Compare-And-Swap)

适用场景

状态标志、简单读写

计数器、复合操作

7. 关键点总结

  • 何时使用 volatile
  • 当变量需要被多个线程共享,并且是单个变量的简单状态标志时(如停止标志、状态标识)。
  • 不涉及复合操作(如 x++ 或 x = x + 1)。
  • 何时不适用 volatile
  • 如果需要保证操作的原子性(如计数器递增),则 volatile 不适合。
  • 涉及多个变量之间的同步或复合操作时,volatile 无法解决问题,需要使用 synchronized 或其他并发工具。
Java碎碎念 文章被收录于专栏

来一杯咖啡,聊聊Java的碎碎念呀

全部评论

相关推荐

来,说点可能被同行“骂”的大实话。🙊当初接数字马力Offer时,朋友都说:“蚂蚁的“内包”公司?你想清楚啊!”但入职快一年后的今天,我反而对他有了不一样的看法!🔹 是偏见?还是信息差!之前没入职之前外面都在说什么岗位低人一等这类。实际上:这种情况不可至否,不能保证每个团队都是其乐融融。但我在的部门以及我了解的周边同事都还是十分好相处的~和蚂蚁师兄师姐之间也经常开一些小玩笑。总之:身份是蚂蚁公司给的,地位是自己挣的(一个傲娇女孩的自述)。🔹 待遇?玩的就是真实!试用期工资全额发!六点下班跑得快(早9晚6或者早10晚7,动态打卡),公积金顶格交。别听那些画饼的,到手的钱和下班的时间才是真的(都是牛马何必难为牛马)。🔹 能不能学到技术?来了就“后悔”!我们拥有权限直通蚂蚁知识库,技术栈多到学不完。说“学不到东西”的人,来了可能后悔——后悔来晚了(哈哈哈哈,可以不学但是不能没有)!💥 内推地址:https://app.mokahr.com/su/ueoyhg❗我的内推码:NTA6Nvs走我的内推,可以直达业务部门,面试流程更快速,进度可查!今天新放HC,之前挂过也能再战!秋招已经正式开始啦~机会就摆在这,敢不敢来试一试呢?(和我一样,做个勇敢的女孩)
下午吃泡馍:数字马力的薪资一般哇,5年经验的java/测试就给人一万出头,而且刚入职第三天就让人出差,而且是出半年
帮你内推|数字马力 校招
点赞 评论 收藏
分享
09-17 19:25
已编辑
太原理工大学 游戏测试
叁六玖:公司名发我,我要这个HR带我打瓦
我的秋招日记
点赞 评论 收藏
分享
评论
3
3
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务