一个熟悉又陌生的关键字:volatile
创始人
2025-07-14 12:21:43
0

Hello,今天了不起带大家了解一下这个熟悉又陌生的关键字:volatile。

在Java多线程编程中,保证线程安全性是至关重要的。而volatile关键字是实现线程安全性的一种关键机制。

为什么熟悉又陌生呢?Java开发者几乎全都用到过这个关键字,但是又不记得什么时候用了它。

1. volatile关键字的原理

volatile关键字主要用于保证变量在多线程环境下的可见性和禁止指令重排序。

当一个变量被volatile修饰时,线程在读取这个变量的值时将直接从主内存中读取,而不是从线程的本地缓存中读取。

同样地,当一个线程修改了volatile变量的值时,这个变化将立即写回到主内存中,而不是仅仅保存在线程的本地缓存中。

2. volatile关键字的作用

  • 保证可见性:在多线程环境下,如果一个线程修改了volatile变量的值,那么其他线程将立即看到这个变化。这样可以避免线程间的数据不一致性问题。
  • 禁止指令重排序:volatile关键字还可以防止编译器和处理器对代码的优化,确保指令按照程序的顺序执行,避免出现意料之外的行为。

3. volatile关键字的正确使用方法

  • 适用场景:volatile适用于那些被多个线程访问但并不涉及复合操作(例如递增操作)的变量。典型的使用场景包括状态标志、控制变量等。
  • 不适用场景:不要将volatile用于需要原子性操作的场景,因为volatile并不能保证原子性。对于需要原子性操作的场景,应该使用锁或者Atomic原子类。

4. 示例代码

public class VolatileExample {
    private volatile boolean flag = false;

    public void startTask() {
        // 启动一个线程来修改flag的值
        new Thread(() -> {
            try {
                Thread.sleep(1000); // 模拟耗时操作
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            flag = true;
            System.out.println("Flag has been set to true.");
        }).start();
    }

    public void monitorTask() {
        // 启动一个线程来检查flag的值
        new Thread(() -> {
            while (!flag) {
                // 循环等待,直到flag变为true
            }
            System.out.println("Flag is now true. Task can proceed.");
        }).start();
    }

    public static void main(String[] args) {
        VolatileExample example = new VolatileExample();
        example.startTask();
        example.monitorTask();
    }
}

在这个示例中,我们有两个线程,一个线程调用startTask()方法来修改flag的值为true,另一个线程调用monitorTask()方法来检查flag的值是否为true。在flag没有被volatile修饰的情况下,可能会出现monitorTask()方法陷入死循环的情况,因为它无法及时获取到flag的最新值。但是,由于flag被volatile修饰,线程可以立即看到flag的变化,因此可以正确地退出循环,从而避免了可能出现的问题。

实际应用

事实上,这个简单的示例代码,在实际使用中,几乎是用不到它这种写法;那到底是怎么使用的这个volatile呢?

其实在Java中,java.util.concurrent.atomic包提供了一组原子类,比如AtomicInteger、AtomicLong、AtomicBoolean等,它们提供了一种无锁的线程安全机制,以确保对变量的操作是原子性的。

当谈到Atomic原子类的实现原理时,CAS(Compare and Swap)操作是其中的关键。CAS是一种乐观锁技术,它涉及比较内存中的值和预期值,如果相等,则使用新值替换内存中的值。在Java中,CAS是通过Unsafe类实现的,它是一种硬件级别的原子性操作。

但是,CAS操作本身无法解决线程可见性的问题,这就是volatile关键字的作用。volatile关键字可以确保变量的写操作立即可见于其他线程,从而解决了线程之间的可见性问题。因此,Atomic原子类是结合了CAS和volatile关键字来实现线程安全。

因此,结合了CAS和volatile关键字,Atomic原子类能够在无锁的情况下实现线程安全,提供了一种高效的并发编程解决方案。CAS保证了原子性,volatile保证了可见性,两者结合起来提供了一个强大的多线程环境下的并发控制机制。

小结

日常开发中,我们一般情况下都是直接使用的Atomic原子类来保证线程安全的情况,并不会去直接使用volatile关键字,乍一看这个volatile还真是熟悉又陌生呢!

相关内容

热门资讯

如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
施耐德电气数据中心整体解决方案... 近日,全球能效管理专家施耐德电气正式启动大型体验活动“能效中国行——2012卡车巡展”,作为该活动的...
Windows恶意软件20年“... 在Windows的早期年代,病毒游走于系统之间,偶尔删除文件(但被删除的文件几乎都是可恢复的),并弹...
20个非常棒的扁平设计免费资源 Apple设备的平面图标PSD免费平板UI 平板UI套件24平图标Freen平板UI套件PSD径向平...
德国电信门户网站可实时显示全球... 德国电信周三推出一个门户网站,直观地实时提供其安装在全球各地的传感器网络检测到的网络攻击状况。该网站...
为啥国人偏爱 Mybatis,... 关于 SQL 和 ORM 的争论,永远都不会终止,我也一直在思考这个问题。昨天又跟群里的小伙伴进行...
《非诚勿扰》红人闫凤娇被曝厕所... 【51CTO.com 综合消息360安全专家提醒说,“闫凤娇”、“非诚勿扰”已经被黑客盯上成为了“木...