【Java面试题】volatile 关键字到底是什么?

0. 背景

在Java的各种面试题中,一个出现频率很高的题就是:

1
volatile 关键字是什么意思?作用是什么?

想必熟悉Java的朋友应该对这个关键字已经有所了解了,同时应该也有很多朋友对这个关键字略有一知半解,只是知道它是“和并发编程相关的”。

那么,本文接下来将会介绍下 volatile 关键字到底是个什么意思。

1. volatile 关键字的语法含义

首先,volatile 是一个关键字,用于修饰成员变量。这个在使用时可以说是非常方便了。

从Java语法的角度来说,在Java语言规范中,是这么说明 volatile 关键字的:

The Java programming language allows threads to access shared variables (§17.1). As a rule, to ensure that shared variables are consistently and reliably updated, a thread should ensure that it has exclusive use of such variables by obtaining a lock that, conventionally, enforces mutual exclusion for those shared variables.

The Java programming language provides a second mechanism, volatile fields, that is more convenient than locking for some purposes.

A field may be declared volatile, in which case the Java Memory Model ensures that all threads see a consistent value for the variable

这段描述,我提取了下里面的主要的内容,大概是以下几个关键点:

1) Java支持多线程访问共享变量;
2) Java可以通过给对象加锁来实现线程互斥访问,进而保证变量访问的多线程安全问题;
3) 除了互斥访问之外,还提供另一种机制,就是用 volatile 关键字来修饰变量,这个机制能在某些特点的场景中很有用;
4) 用volatile 修饰的变量,可以确保它的可见性

以上几个关键点,前3个都好理解,比如加锁来做线程同步等等,只有第4点,啥叫能保证可见性可见性又是个啥?

2. 什么是可见性问题?

要说到可见性是什么,其实这个问题来源于CPU的缓存一致性的问题。

现代的CPU都是有高速缓存的,而且还是有多级缓存的。为什么叫高度缓存呢?这个是相对内存来说的,高度缓存的读写速度要比内存高很多,这样设计也是为了提高CPU的速度,如果没有这个CPU内的缓存的话,那涉及到和内存读写交互的话,CPU大部分时间都是在等待着内存数据的读写。

同时,现代CPU基本都是多核的了,还有单核心上的超线程技术,这样就相当于有多个CPU同时和内存进行读取操作,每一个CPU核心里面都有各自的缓存,那么如何保证每一个读取到的数据都是新的呢?

这个就是可见性问题。

java-volatile-img1
(缓存一致性(图片来自维基百科))

上面的Client可以代表一个核心,每一个核心在从内存读取数据的时候,会先把数据复制到自己的缓存中一份,缓存一致性就是需要保证在多个里面的缓存是正确的。

正是基于以上的设计,才会有JVM中的可见性的问题。

JVM是多线程的环境,多个线程在实际运行的时候,有可能是在不同的CPU核心中运行的,所以每一个线程在读取内存的数据的时候,也有可能是读取的线程内部的缓存,这个时候,假如其他某个线程修改了这个变量,对于这线程来说是不知情的,也就是不可见的

java-volatile-img2

3. JMM中关于volatile的可见性保证

JVM为了解决上面的可见性问题,在规范层面进行了约束,新增了 volatile 关键字的机制来解决这个问题。它能保证,某一个线程对变量修改了以后,对其他的线程时可见的。

这样的设计,针对一写多读 的并发环境,是非常有帮助的。由于只有一个线程在写变量,加上锁的话会对性能影响比较大。如果直接把共享变量声明成为 volatile 的就可以实现可见性了。

volatile 的机制,只是规范层的约束,那么底层的实现呢?这个实现的话,就是基于底层的CPU的MESI协议,这个协议就是专门用于解决CPU的多个核心之间的缓存的一致性问题的,有了它就可以做到啦,这里不再展开了。

参考资料:
https://www.cnblogs.com/1994july/p/12051965.html

http://ifeve.com/java-volatile%e5%85%b3%e9%94%ae%e5%ad%97/

https://docs.oracle.com/javase/specs/jls/se12/html/jls-8.html#jls-8.3.1.4

https://docs.oracle.com/javase/specs/jls/se12/html/jls-17.html#jls-17.4

https://en.wikipedia.org/wiki/Cache_coherence

https://zh.wikipedia.org/zh-hans/MESI%E5%8D%8F%E8%AE%AE

坚持原创技术分享,您的支持将鼓励我继续创作!