深入理解java中的volatile关键字

简介: 深入理解java中的volatile关键字

深入理解 volatile 关键字

在 Java 多线程编程中,volatile 关键字是一个轻量级的同步机制,用于确保变量在多个线程之间的可见性和有序性。本文将深入解析 volatile 的原理、使用场景以及其在并发编程中的作用。

volatile 可以确保当一个线程更新共享变量时,更新操作对其他线程马上可见。当一个变量被声明为 volatile 时,线程在写入变量时不会把值缓存在寄存器或者其他地方,而是会把值刷新回主内存。

当其他线程读取该共享变量时,会从主内存重新获取最新值,而不是使用当前线程的工作内存中的值。

1. 什么是 volatile?

volatile 是 Java 提供的一种轻量级同步机制,用于修饰成员变量。被 volatile 修饰的变量在每次被线程访问时,都强制从主内存(Main Memory)中读取,而不是从线程的本地缓存(Local Cache)中读取,并在每次更新时立即刷新到主内存中,从而保证了变量的可见性和有序性。

2. volatile 的内存语义

  • 可见性:当一个线程修改了 volatile 变量的值,新值会立即被刷新到主内存中,其他线程读取该变量时会立即从主内存中读取到最新的值。
  • 有序性:禁止指令重排序优化。即在读写 volatile 变量时,通过内存屏障(Memory Barrier)来防止指令重排序,从而保证代码执行的顺序性。

3. volatile 的原理

volatile 的实现依赖于内存屏障(Memory Barrier),这是一种 CPU 指令,用于禁止特定的指令重排序。现代 CPU 和编译器会对指令进行优化,通过重排序提高性能,但这可能导致多线程程序中的可见性和有序性问题。内存屏障的引入确保了对 volatile 变量的读写操作在多线程环境中的正确性。


在 Java 中,JVM 在生成字节码时会在 volatile 变量的读写操作前后插入内存屏障,从而实现上述内存语义。


感兴趣的同学可以学习下java内存模型链接地址,便于加深了解


Tips:在访问 volatile 变量时不会执行加锁操作,因此也就不会使执行线程阻塞,因此 volatile 变量是一种比 sychronized 关键字更轻量级的同步机制。

4. volatile 的使用场景

4.1 状态标志:用于表示程序或线程的状态变化,如停止标志、开关等。

public class VolatileFlag {
    private volatile boolean flag = false;

    public void stop() {
        flag = true;
    }

    public void run() {
        while (!flag) {
            // 业务逻辑
        }
    }
}

4.2 单例模式: 双重检查锁定(Double-Checked Locking)实现的单例模式。

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;
    }
}

4.3 轻量级的读写锁: 用于实现轻量级的读写锁,如单个写线程和多个读线程的场景。

5. volatile 的局限性

虽然 volatile 可以保证变量的可见性和有序性,但它并不能保证原子性。例如,对于 volatile 修饰的计数器变量,以下操作并不是线程安全的:

public class VolatileCounter {
    private volatile int count = 0;

    public void increment() {
        count++; // 非线程安全
    }
}

对于这类需要原子性操作的场景,应该使用 AtomicInteger 或 synchronized 关键字来确保线程安全。

6. 实际应用

使用 volatile 实现简单的线程安全状态控制

public class VolatileExample {
    private volatile boolean running = true;

    public void start() {
        Thread thread = new Thread(() -> {
            while (running) {
                // 执行任务
                System.out.println("Thread is running...");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
            System.out.println("Thread stopped.");
        });
        thread.start();
    }

    public void stop() {
        running = false;
    }

    public static void main(String[] args) throws InterruptedException {
        VolatileExample example = new VolatileExample();
        example.start();
        Thread.sleep(5000); // 运行5秒后停止线程
        example.stop();
    }
}

在这个示例中,running 变量被 volatile 修饰,确保在多个线程之间的可见性。当主线程调用 stop 方法时,工作线程能够立即看到 running 的变化,从而停止运行。

7.0 总结

volatile 是 Java 中一种轻量级的同步机制,通过保证变量的可见性和有序性,提供了比 synchronized 更高效的线程间通信方式。尽管如此,volatile 也有其局限性,不能保证原子性操作。因此,在实际应用中,应根据具体场景选择合适的同步机制,以确保并发程序的正确性和性能。


目录
相关文章
|
5月前
|
存储 缓存 Java
【高薪程序员必看】万字长文拆解Java并发编程!(5):深入理解JMM:Java内存模型的三大特性与volatile底层原理
JMM,Java Memory Model,Java内存模型,定义了主内存,工作内存,确保Java在不同平台上的正确运行主内存Main Memory:所有线程共享的内存区域,所有的变量都存储在主存中工作内存Working Memory:每个线程拥有自己的工作内存,用于保存变量的副本.线程执行过程中先将主内存中的变量读到工作内存中,对变量进行操作之后再将变量写入主内存,jvm概念说明主内存所有线程共享的内存区域,存储原始变量(堆内存中的对象实例和静态变量)工作内存。
180 0
|
7月前
|
设计模式 存储 SQL
【Java并发】【volatile】适合初学者体质的volatile
当你阅读dalao的框架源码的时候,你是否会见到这样一个关键字 - - - volatie,诶,你是否会好奇,为什么要加它?加了它有什么作用?
212 14
【Java并发】【volatile】适合初学者体质的volatile
|
7月前
|
存储 缓存 安全
【原理】【Java并发】【volatile】适合初学者体质的volatile原理
欢迎来到我的技术博客!我是一名热爱编程的开发者,梦想是写出高端的CRUD应用。2025年,我正在沉淀自己,博客更新速度也在加快。在这里,我会分享关于Java并发编程的深入理解,尤其是volatile关键字的底层原理。 本文将带你深入了解Java内存模型(JMM),解释volatile如何通过内存屏障和缓存一致性协议确保可见性和有序性,同时探讨其局限性及优化方案。欢迎订阅专栏《在2B工作中寻求并发是否搞错了什么》,一起探索并发编程的奥秘! 关注我,点赞、收藏、评论,跟上更新节奏,让我们共同进步!
331 8
【原理】【Java并发】【volatile】适合初学者体质的volatile原理
|
8月前
|
缓存 安全 Java
Volatile关键字与Java原子性的迷宫之旅
通过合理使用 `volatile`和原子操作,可以在提升程序性能的同时,确保程序的正确性和线程安全性。希望本文能帮助您更好地理解和应用这些并发编程中的关键概念。
196 21
|
6月前
|
存储 安全 Java
深入理解 Java 中的 instanceof 关键字
本文深入解析了 Java 中的 `instanceof` 关键字,探讨其在类型判断中的作用。作为二元操作符,`instanceof` 可用于检查对象是否为某类实例或实现特定接口,避免类型转换异常 (`ClassCastException`)。文章通过多态性下的类型判断、安全类型转换、接口实现检测及集合元素类型判定等实际应用场景,展示了 `instanceof` 的强大功能。掌握该关键字可提高代码健壮性,确保运行时类型安全。
433 0
|
7月前
|
Java C语言
课时8:Java程序基本概念(标识符与关键字)
课时8介绍Java程序中的标识符与关键字。标识符由字母、数字、下划线和美元符号组成,不能以数字开头且不能使用Java保留字。建议使用有意义的命名,如student_name、age。关键字是特殊标记,如蓝色字体所示。未使用的关键字有goto、const;特殊单词null、true、false不算关键字。JDK1.4后新增assert,JDK1.5后新增enum。
121 4
|
10月前
|
存储 缓存 Java
Java 并发编程——volatile 关键字解析
本文介绍了Java线程中的`volatile`关键字及其与`synchronized`锁的区别。`volatile`保证了变量的可见性和一定的有序性,但不能保证原子性。它通过内存屏障实现,避免指令重排序,确保线程间数据一致。相比`synchronized`,`volatile`性能更优,适用于简单状态标记和某些特定场景,如单例模式中的双重检查锁定。文中还解释了Java内存模型的基本概念,包括主内存、工作内存及并发编程中的原子性、可见性和有序性。
267 5
Java 并发编程——volatile 关键字解析
|
9月前
|
Java 编译器 开发者
Java中的this关键字详解:深入理解与应用
本文深入解析了Java中`this`关键字的多种用法
1502 9
|
9月前
|
JSON Java 数据挖掘
利用 Java 代码获取淘宝关键字 API 接口
在数字化商业时代,精准把握市场动态与消费者需求是企业成功的关键。淘宝作为中国最大的电商平台之一,其海量数据中蕴含丰富的商业洞察。本文介绍如何通过Java代码高效、合规地获取淘宝关键字API接口数据,帮助商家优化产品布局、制定营销策略。主要内容包括: 1. **淘宝关键字API的价值**:洞察用户需求、优化产品标题与详情、制定营销策略。 2. **获取API接口的步骤**:注册账号、申请权限、搭建Java开发环境、编写调用代码、解析响应数据。 3. **注意事项**:遵守法律法规与平台规则,处理API调用限制。 通过这些步骤,商家可以在激烈的市场竞争中脱颖而出。
|
10月前
|
安全 Java Kotlin
Java多线程——synchronized、volatile 保障可见性
Java多线程中,`synchronized` 和 `volatile` 关键字用于保障可见性。`synchronized` 保证原子性、可见性和有序性,通过锁机制确保线程安全;`volatile` 仅保证可见性和有序性,不保证原子性。代码示例展示了如何使用 `synchronized` 和 `volatile` 解决主线程无法感知子线程修改共享变量的问题。总结:`volatile` 确保不同线程对共享变量操作的可见性,使一个线程修改后,其他线程能立即看到最新值。
246 7