Java中的volatile关键字

JAVA语言与项目相关讨论
发表回复
头像
IOsetting
论坛管理员
论坛管理员
帖子: 3628
注册: 2006-10-17 1:48

Java中的volatile关键字

帖子 IOsetting » 2018-12-01 22:32

可以参考这篇文章, 介绍得非常详细: http://tutorials.jenkov.com/java-concur ... atile.html
进一步的阅读: Java语言规范的"线程和锁"这一章 https://docs.oracle.com/javase/specs/jl ... ls-17.html

volatile关键字用于将变量标识为"存储于主内存". 更精确些, 就是每一次读取变量值的时候, 都必须从计算机的主内存中读取, 而不能从CPU的缓存, 每一次写变量值的时候, 也必须写到主内存, 而不是CPU的缓存.

Volatile附带的"变化可见度"特性
  • 如果Thread A 写了一个volatile变量 并且Thread B读取了这个volatile变量, 那么所有在写入这个变量前对A"可见"的变量, 在B读取这个变量之后, "变化"变得对B可见.
  • 如果Thread A读取了一个volatile变量, 那么所有在A读取这个变量之前对A"可见"的变量, 在读取后会从主内存中重新读取.
    编译时对volatile的处理, 在JDK5以及之后是不同的, 在JDK4时, 对volatile变量的读写与对其他变量的读写指令, 在编译优化阶段可能会被调换顺序, 在JDK5之后保证了发生在volatile变量之前的读写, 不会被调整到volatile变量的读写之后.
JDK5以及之后的顺序保证(Happens-Before Guarantee)
  • 如果代码中对某个变量的读取和写入发生在对volatile变量的写入之前, 那么编译后这个读写操作保证不会被调整到对volatile的写入之后. 注意这仅仅是保证发生在volatile写入之前的操作不会放到后面, 但是不能保证volatile写入之后的操作不会被放到前面.
  • 如果代码中对某个变量的读取和写入发生在对volatile变量的读取之后, 那么编译后这个读写操作保证不会被调整到对volatile的读取之前. 注意这也不能保证volatile读取之前的操作不会被放到后面.
在有写入的场景下, volatile是不够的
需要用synchronized来保证写入不会互相覆盖, 或者使用AtomLong 或 AtomicReference 这样的原子操作类型数据.

发表回复