【问题标题】:Volatile Keyword & the thread local memory [closed]易失性关键字和线程本地内存[关闭]
【发布时间】:2023-12-31 08:30:01
【问题描述】:

我对 Java 中 volatile 关键字的用法感到困惑。我在互联网上阅读了很多文章,但仍然一无所获。我脑子里有很多问题想问:

首先,*和许多博客都说所有volatile 变量都存储在一个线程本地内存,在所有线程共享的主内存上!我有点困惑,它们是指stack memory 吗?我知道每个线程都有自己的stack memory,它存储自己的原始文字和对象引用。

如果是这样,那么如果 volatile 变量是对象引用而不是原始文字会发生什么?我猜所有的对象都存储在堆空间而不是堆栈内存中。

其次,您能否通过示例详细说明volatile 关键字的工作原理以及我们应该何时使用它?

【问题讨论】:

标签: java jvm thread-safety heap-memory volatile


【解决方案1】:

首先,*和许多博客都说所有易失性变量都存储在线程本地内存中,而不是所有线程共享的主内存。

这是不正确的。可变字段是实例或类(静态)变量,存储在堆中。

他们可能指的是特定于单个处理器/内核的高速缓存内存......但这是特定于硬件的事情。但这绝对不是“线程本地的”。这个词的意思完全不同。

如果是这样,那么如果 volatile 变量是对象引用而不是原始字面量会发生什么?

没什么特别的。你的假设是错误的。

易失性变量不存储在堆栈中。实际上,如果您尝试将 volatile 关键字用于局部变量,您将收到编译错误。 (这是没有意义的。堆栈上的变量只对一个线程可见。可变语义是关于由不同线程共享的变量。)

我知道每个线程都有自己的堆栈内存,它存储自己的原始文字和对象引用。

线程栈中存储的是:

  • 方法的局部变量,
  • 方法的参数,
  • 方法的返回地址等,以便 CPU 在调用返回时知道去哪里,并且(可能)
  • JIT 编译器认为不需要将本地对象的状态存储在堆中。

方法的原始文字通常嵌入在代码本身中。字符串文字也在其他地方。 (当这些文字被分配给局部变量时,它们将被保存在堆栈中......)

其次,您能否通过一个示例详细说明 volatile 关键字的工作原理以及我们应该何时使用它?

检查 cmets 和相关问题......或谷歌“java volatile example”。解释是多余的。

【讨论】:

  • 你的答案+1。但是,您没有在“存储在线程堆栈上的内容是:”中提到在方法内创建的对象的参考值。这是否意味着在方法中创建的对象将存储在堆栈本身中?不在堆中?
  • 在方法中创建的对象的引用不需要特别提及。它们可能存储在局部变量中(在堆栈中......已经覆盖),或者在类变量、实例变量或数组中(在堆中)。
  • 我的最后一个要点是指一些 JIT 编译器在启用“转义分析”时可能执行的特定优化。在这种情况下,整个对象存储在堆栈内存中。如果 JIT 编译器可以推断出有问题的对象不能从当前方法中“逃脱”,则可以执行此优化。