Wrayの知识库 Wrayの知识库
首页
  • Java 基础
  • Java 集合
  • Java 并发
  • Java IO
  • JVM
  • Spring Framework
  • Spring Boot
  • Spring Cloud
  • Spring Security
  • MySQL
  • Redis
  • MacOS
  • Linux
  • Windows
  • 纸质书
  • 电子书
  • 学习课程
疑难杂症
GitHub (opens new window)
首页
  • Java 基础
  • Java 集合
  • Java 并发
  • Java IO
  • JVM
  • Spring Framework
  • Spring Boot
  • Spring Cloud
  • Spring Security
  • MySQL
  • Redis
  • MacOS
  • Linux
  • Windows
  • 纸质书
  • 电子书
  • 学习课程
疑难杂症
GitHub (opens new window)
  • Java基础

    • Java概述
    • Java语法
    • 面向对象编程
    • Java数组
    • String字符串
    • 异常处理
  • Java集合

    • Java集合概述
    • ArrayList
    • LinkedList
    • HashMap
    • LinkedHashMap
    • HashSet
    • TreeMap
    • Queue&Deque
  • Java并发

    • Java并发概述
    • 线程与进程
    • Thread类与线程生命周期
    • 线程安全
    • synchronized关键字
    • volatile关键字
      • 1. volatile 的基本概念
      • 2. volatile 的使用场景
      • 3. volatile 的特点与局限性
      • 4. volatile 与 synchronized 的比较
      • 5. volatile 的内存语义
      • 6. 适用场景总结
      • 7. volatile 的局限性
      • 8. 总结
    • Java内存模型(JMM)
    • 线程间通信
    • 线程池
    • 并发工具类
    • 原子操作类Atomic
    • 并发锁
    • 并发容器
    • ConcurrentHashMap
    • BlockingQueue
    • CopyOnWriteArrayList
    • ThreadLocal
    • Fork/Join框架
    • ScheduledThreadPoolExecutor
    • CompletableFuture
  • Java IO

    • Java IO概述
  • JVM

    • JVM概述
  • Java
  • Java并发
Wray
2024-10-31
目录

volatile关键字

volatile 关键字是 Java 中用于保证变量可见性的重要工具。它用于多线程环境下,使得不同线程对共享变量的修改能够立即被其他线程看到,从而避免内存可见性问题。

# 1. volatile 的基本概念

  • 可见性:volatile 确保了当一个线程修改了 volatile 变量的值,其他线程能够立刻看到这个修改,保证了变量在多个线程间的可见性。
  • 禁止指令重排序优化:volatile 还可以防止编译器和 CPU 对变量的操作进行指令重排序,从而保证程序的执行顺序符合预期。

# 2. volatile 的使用场景

  • 状态标志:volatile 适用于那些需要线程之间共享状态标志的场景,例如使用 volatile 修饰一个布尔变量,用于控制线程的运行状态。

    private volatile boolean running = true;
    
    public void stopRunning() {
        running = false;
    }
    
    • 当一个线程调用 stopRunning() 方法将 running 设置为 false 时,其他正在检查 running 状态的线程会立即看到这个变化。
  • 单例模式的双重检查锁定:在实现单例模式时,使用 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 的特点与局限性

  • 只保证可见性,不保证原子性:volatile 保证了对变量的可见性,但不能保证操作的原子性。例如,对于 count++ 这样的操作,volatile 无法保证线程安全,因为它涉及读取、修改和写入多个步骤。

    • 示例问题:即使 count 被声明为 volatile,多个线程同时执行 count++ 时,仍然可能会发生竞态条件,导致最终结果不符合预期。
  • 轻量级的同步机制:volatile 是一种相对轻量级的同步机制,与 synchronized 相比,它不需要上下文切换和线程阻塞,因此在某些情况下性能更高。但 volatile 只能用于修饰变量,不能用于同步更复杂的代码块或方法。

# 4. volatile 与 synchronized 的比较

  • 可见性:

    • volatile 能够保证变量在多线程之间的可见性。
    • synchronized 也能保证可见性,因为在一个线程释放锁之前,会将共享变量的值刷新到主内存,其他线程获得锁后可以看到最新的值。
  • 原子性:

    • volatile 不能保证操作的原子性,只能保证读取和写入的可见性。
    • synchronized 通过加锁的方式,可以保证方法或代码块的原子性,即同一时间只有一个线程可以执行被同步的方法。
  • 使用场景:

    • volatile 适用于对变量进行简单的读取和写入操作,且这些操作之间没有依赖关系的场景。
    • synchronized 更适合涉及多个步骤的复杂操作,例如需要对共享资源进行修改时。

# 5. volatile 的内存语义

  • 读写的可见性:使用 volatile 修饰的变量在被写入时,JVM 会强制将该变量的最新值刷新到主内存中;而当其他线程读取这个变量时,JVM 会强制从主内存中读取最新的值,而不是从线程的本地缓存中读取。
  • 内存屏障:volatile 在底层会使用内存屏障来保证指令的有序性和内存的可见性。
    • 写屏障:当写入 volatile 变量时,会插入一个写屏障,保证在写入之后的指令不会被重排序到写入之前。
    • 读屏障:当读取 volatile 变量时,会插入一个读屏障,确保在读取之前的指令不会被重排序到读取之后。

# 6. 适用场景总结

  • 适用于简单状态标志的控制:当需要一个变量在多个线程之间共享且作为状态标志使用时,可以使用 volatile。例如,用于控制线程的启动和停止。
  • 不适用于复合操作:volatile 不能替代锁,无法用于复合操作(如自增、自减等)。在涉及复合操作时,需要使用 synchronized 或 Lock 来保证线程安全。
  • 双重检查锁定的单例模式:在双重检查锁定的单例模式中使用 volatile,防止指令重排序,确保对象的正确初始化。

# 7. volatile 的局限性

  • 不保证原子性:对于 volatile 变量的读取和写入是原子的,但对复合操作(如自增、自减等)不保证原子性,不能防止竞态条件。
  • 复杂同步场景:volatile 仅适用于轻量级的同步场景。如果需要涉及多步的复杂同步控制,应该使用 synchronized 或其他锁机制。

# 8. 总结

volatile 关键字是 Java 中用于实现变量可见性的重要工具。它可以确保变量在多线程之间的修改是立即可见的,并且防止指令重排序。但需要注意的是,volatile 不能保证操作的原子性,因此不适合用于需要复合操作的场景。在实际使用中,开发者需要根据具体的场景选择合适的同步机制,以确保线程安全。理解 volatile 的适用场景和局限性,有助于编写高效、安全的并发程序。

上次更新: 2024/11/01, 13:45:14
synchronized关键字
Java内存模型(JMM)

← synchronized关键字 Java内存模型(JMM)→

Copyright © 2023-2024 Wray | 鄂ICP备2024050235号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式