Volatile

源码 2024-10-9 00:59:47 28 0 来自 中国
volatile 是 Java 中的关键字,是一个变量修饰符,被用来修饰会被差别线程访问和修改的变量
语义

一旦一个共享变量被 volatile 修饰之后,就具备两层语义

  • 保证了差别线程对这个变量举行操作时的可见性,即一个线程修改了某个变量的值,这个新值对其他线程来说是立刻可见的
  • 克制举行指令重排序
作用


  • 原子性
    volatile 仅仅保证对恣意单个 volatile变量的读/写具有原子性,但雷同于volatile++这种复合操作以及多个volatile的读写不具有原子性
  • 可见性
    对一个 volatile 变量的读,总是能看到(恣意线程)对这个 volatile 变量末了的写入
  • 有序性
    对 volatile 修饰的变量的读写操作前后加上各种特定的内存屏蔽来克制指令重排序,保证有序性
实现原理

字节码层面

ACC_VOLATILE
JVM层面(规范)

为了实现 volatile 的内存语义,JMM会限定特定范例的编译器和处置惩罚器重排序,JMM会针对编译器订定 volatile 重排序规则表,“NO”表现克制重排序。

编译器在天生字节码时,会在指令序列中插入内存屏蔽来克制特定范例的处置惩罚器重排序。

  • 在每个 volatile 写操作的 前面插入StoreStore屏蔽,反面插入StoreLoad屏蔽

  • 在每个 volatile 读操作的 反面插入LoadLoad 和 LoadStore屏蔽
    3.png
Hotspot实现

bytecodeinterpreter.cpp0
int field_offset = cache->f2_as_index();if (cache->is_volatile()) {    if (support_IRIW_for_not_multiple_copy_atomic_cpu) {        OrderAccess::fence();    }}orderaccess_linux_x86.inline.hpp
inline void OrderAccess::fence() {   // always use locked addl since mfence is sometimes expensive#ifdef AMD64  __asm__ volatile ("lock; addl $0,0(%%rsp)" : : : "cc", "memory");#else  __asm__ volatile ("lock; addl $0,0(%%esp)" : : : "cc", "memory");#endif  compiler_barrier();}假如硬件架构本身已经保证了内存可见性(单核处置惩罚器、同等性充足的内存模子),大概硬件架构本身不举行处置惩罚器重排序,大概有更强的重排序语义(可以或许分析多核间的数据依赖),那么volatile就是一个空标志,不会插入干系语义的内存屏蔽。
检察源代码,可以看到在汇编层面,带有 volatile 修饰的变量前面会有lock add1 $0x0, (%rsp)这么一串指令,由此可见 volatile 是通过LOCK指令前缀来到达内存屏蔽的作用。
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-10-18 14:16, Processed in 0.199940 second(s), 35 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表