【发布时间】:2022-01-23 11:22:53
【问题描述】:
我了解 Java 关键字 volatile 用于多线程上下文;主要目的是从内存中读取而不是从缓存中读取,或者即使从缓存中读取,也会先更新。
在下面的例子中,没有多线程的概念。我想了解变量 i 是否会作为代码优化的一部分被缓存,从而从 cpu 缓存而不是内存中读取?如果是的话,如果变量声明为volatile,肯定会从内存中读取吗?
我通过添加和删除 volatile 关键字多次运行该程序;但是,由于 for 循环没有固定的时间,因此当变量声明为 volatile 时是否消耗更多时间,我无法得出结论。
我只想看到,从 CPU 缓存中花费的时间实际上比它声明为 volatile 时要少。
我的理解是否正确?如果是,我怎样才能看到这个概念在工作中,并很好地记录了 CPU 缓存读取和内存读取的时间?
import java.time.Duration;
import java.time.Instant;
public class Test {
volatile static int i=0;
// static int i=0;
public static void main(String[] args) {
Instant start = Instant.now();
for (i=0; i<838_860_8; i++) { // 2 power 23; ~ 1 MB CPU Cache
System.out.println("i:" + i);
}
Instant end = Instant.now();
long timeElapsed = Duration.between(start, end).getSeconds();
System.out.println("timeElapsed: " + timeElapsed + " seconds.");
}
}
【问题讨论】:
-
不确定你的基准,没有重大变化,测试很多。你确定 JVM 已经离开解释模式了吗?不相信您的代码甚至会被 JIT 化
-
是的,该变量将从内存中读取,因为 volatile 保证 JVM 从内存中读取它。至于基准测试是@Bor
-
@BoristheSpider 我只是假设变量 i 将存储在 CPU 缓存中,主要是因为在任何给定时间点,它的值都是
-
变量中存储的值与它是否存储在缓存或主内存中无关。您可能正在考虑一个大型数组,它不能作为一个整体放入缓存中,但现在您只有一个 int 变量,它只占用 4 个字节的内存。
-
按逻辑,如果使用
volatile,肯定有一些缺点,否则就是默认的,甚至不存在。通过 JMH 测试,差异很大(循环系数为 20 并对变量 {println not used} 求和)