volatile 变量提供什么保证?

简介: 【8月更文挑战第21天】

在 Java 编程中,volatile关键字是一个重要的特性,它为变量提供了特定的保证,在多线程环境下起着关键的作用。

一、可见性保证

  1. 多线程环境下的变量可见性问题

    • 在多线程编程中,每个线程都有自己的工作内存,线程对变量的操作首先是在自己的工作内存中进行,然后再同步到主内存中。这就可能导致一个问题:当一个线程修改了一个共享变量的值后,其他线程可能无法立即看到这个修改。
    • 例如,有两个线程 A 和 B,它们都访问同一个共享变量x。线程 A 修改了x的值,但线程 B 可能仍然在使用旧的值,因为线程 B 的工作内存中可能还保留着x的旧副本。
  2. volatile 确保可见性

    • volatile关键字可以确保被它修饰的变量的修改对所有线程立即可见。当一个线程修改了一个volatile变量的值时,JVM 会立即将这个修改同步到主内存中,并且会使其他线程中缓存的该变量的值无效,迫使其他线程重新从主内存中读取该变量的值。
    • 例如,如果变量x被声明为volatile,那么当线程 A 修改了x的值后,线程 B 在下一次访问x时,一定会看到线程 A 所做的修改。

二、禁止指令重排序保证

  1. 指令重排序的概念

    • 在现代处理器和编译器中,为了提高性能,可能会对代码进行指令重排序。指令重排序是指在不改变程序语义的前提下,改变指令的执行顺序。
    • 例如,在一个方法中,可能有以下代码:
      int a = 1;
      int b = 2;
      int c = a + b;
      
    • 编译器或处理器可能会对这些指令进行重排序,先执行int c = a + b;,再执行int a = 1;int b = 2;,只要最终的结果是正确的,这种重排序在单线程环境下是没有问题的。
  2. volatile 禁止特定的指令重排序

    • volatile关键字可以禁止特定的指令重排序。当一个变量被声明为volatile时,JVM 会确保对该变量的读写操作不会被重排序到其他对该变量有依赖关系的操作之前或之后。
    • 例如,考虑以下代码:
      volatile boolean flag = false;
      int result = 0;
      // 线程 1
      if (flag) {
             
      result = computeValue();
      }
      // 线程 2
      flag = true;
      
    • 在这个例子中,如果flag没有被声明为volatile,那么编译器或处理器可能会对线程 1 和线程 2 的代码进行重排序,导致线程 1 在flag被设置为true之前就执行了if语句,从而得到错误的结果。但是,如果flag被声明为volatile,JVM 会确保线程 2 对flag的写操作先于线程 1 对flag的读操作,从而避免了这个问题。

三、使用 volatile 的注意事项

  1. 不能替代同步机制

    • 虽然volatile提供了可见性和禁止指令重排序的保证,但它不能替代传统的同步机制(如synchronized关键字或ReentrantLock)。volatile只能保证单个变量的可见性和原子性,而同步机制可以确保一段代码块的原子性和可见性。
    • 例如,如果需要对多个变量的操作进行原子性保证,或者需要对一段复杂的代码进行同步,那么应该使用同步机制而不是仅仅依赖volatile
  2. 性能考虑

    • 使用volatile可能会带来一定的性能开销,因为它需要额外的操作来确保变量的可见性和禁止指令重排序。在一些对性能要求非常高的场景下,需要谨慎使用volatile,并进行充分的性能测试。

四、总结

volatile关键字为变量提供了可见性和禁止指令重排序的保证。在多线程环境下,它可以确保一个线程对volatile变量的修改立即对其他线程可见,并且可以防止特定的指令重排序。然而,volatile不能替代传统的同步机制,并且在使用时需要考虑性能问题。正确理解和使用volatile关键字对于编写正确、高效的多线程程序至关重要。

目录
相关文章
|
设计模式 前端开发 JavaScript
观察者模式 vs 发布-订阅模式:两种设计模式的对决!
欢迎来到前端入门之旅!这个专栏是为那些对Web开发感兴趣、刚刚开始学习前端的读者们打造的。无论你是初学者还是有一些基础的开发者,我们都会在这里为你提供一个系统而又亲切的学习平台。我们以问答形式更新,为大家呈现精选的前端知识点和最佳实践。通过深入浅出的解释概念,并提供实际案例和练习,让你逐步建立起一个扎实的基础。无论是HTML、CSS、JavaScript还是最新的前端框架和工具,我们都将为你提供丰富的内容和实用技巧,帮助你更好地理解并运用前端开发中的各种技术。
|
2月前
|
JSON 关系型数据库 Apache
十亿 JSON 秒级响应:Apache Doris vs ClickHouse,Elasticsearch,PostgreSQL
JSONBench 是一个为 JSON 数据而生的数据分析 Benchmark,在默认设置下,Doris 的性能表现是 Elasticsearch 的 2 倍,是 PostgreSQL 的 80 倍。调优后,Doris 查询整体耗时降低了 74%,对比原榜单第一的 ClickHouse 产品实现了 39% 的领先优势。本文详细描述了调优思路与 Doris 调优前后的性能表现,欢迎阅读了解~
478 0
十亿 JSON 秒级响应:Apache Doris vs ClickHouse,Elasticsearch,PostgreSQL
|
2月前
|
移动开发 小程序 开发工具
揭秘微信/支付宝6大支付方式:从扫码到刷脸,谁在偷偷赚你的手续费?优雅草卓伊凡
揭秘微信/支付宝6大支付方式:从扫码到刷脸,谁在偷偷赚你的手续费?优雅草卓伊凡
278 0
揭秘微信/支付宝6大支付方式:从扫码到刷脸,谁在偷偷赚你的手续费?优雅草卓伊凡
|
NoSQL Java Redis
SpringBoot2.0整合Redis高可用之Sentinel哨兵
本篇博文分享的是一主二从三哨兵模式。至于为什么用三个哨兵,同第一段。本文是模拟环境,都是一个服务器上面。
1132 0
|
存储 Java 开发者
Java 中的线程局部变量是什么?
【8月更文挑战第21天】
167 0
|
移动开发 前端开发 JavaScript
|
负载均衡 监控 Java
SpringCloud常见面试题(一):SpringCloud 5大组件,服务注册和发现,nacos与eureka区别,服务雪崩、服务熔断、服务降级,微服务监控
SpringCloud常见面试题(一):SpringCloud 5大组件,服务注册和发现,nacos与eureka区别,服务雪崩、服务熔断、服务降级,微服务监控
23239 7
SpringCloud常见面试题(一):SpringCloud 5大组件,服务注册和发现,nacos与eureka区别,服务雪崩、服务熔断、服务降级,微服务监控
|
监控 Java 开发者
Spring Cloud中的服务熔断与降级
Spring Cloud中的服务熔断与降级
|
前端开发 UED
【Web 前端】防抖与节流的区别
【4月更文挑战第22天】【Web 前端】防抖与节流的区别
|
消息中间件 安全 Java
Java 中的线程与进程之区别
【8月更文挑战第22天】
199 0