【问题标题】:volatile mutable object that doesn't change after assignmentvolatile 可变对象,在赋值后不会改变
【发布时间】:2021-11-19 07:40:52
【问题描述】:

场景:

class Foo {

    volatile Bar bar;
}

class Bar {

    int baz;
}

for (int i = 0; i < n; i++) {
    Bar bar = new Bar();
    bar.baz = 1;
    foo.bar = bar;
} 

如果 Bar 不是不可变的(baz 不是 final 或 volatile)但 baz 在 bar 分配后永远不会改变,是否保证 baz 变量始终可见?

【问题讨论】:

  • 你在哪里运行 for 循环?
  • @Renis1235 任何地方,在读取值的线程以外的某个线程中
  • 你有什么问题?
  • @Digsb 问题在代码下

标签: java thread-safety


【解决方案1】:

volatile 仅应用于您定义它的变量。

如果您需要确保您的代码也适用于嵌套变量,您还需要定义它们volatile

作为替代方案,您可以将访问Bar 变量和嵌套变量的代码封装在synchronized 块中。

volatile 关键字允许变量取自主内存,而不是取自 cpu 的注册表。这使得:

... volatile 修饰符保证任何读取字段的线程 将看到最近写入的值。 - 乔什·布洛赫

这发生在声明为volatile 的变量上,而不是内部字段。您可以在 baz 变量上使用 volatile 关键字,在这种情况下您可以确定代码可以正常工作。

【讨论】:

  • 谢谢,所以答案是否定的?即使我在 bar.baz 分配之后将 bar 分配给 volatile foo.bar,也不能保证 bar.baz 是可见的吗?
  • 问题不在于是否可见,而在于值是否一致。如果两个线程同时在 baz 的值上工作,则可能有不一致的值。我更新答案以显示它
  • 是的,我能理解。但是假设我有 1 个线程发布一些全局配置(Bar 类),而其他线程只读取该配置,我唯一的要求是在 foo.bar 分配 bar.baz 之后具有最新值(我没有竞争条件)。我认为它仍然不安全?
  • 你需要将 baz 定义为 volatile
  • 感谢您的回答。我最近遇到了这个与我的非常相似的问题:stackoverflow.com/questions/10357823/… 但接受的答案却相反:“如果您要填充一个全新的 HashMap,然后将其分配给现有变量,那么您可以使用 volatile”您能否参考对此(HashMap 显然不是线程安全的)?
猜你喜欢
  • 2021-05-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-08
  • 2018-07-20
  • 2021-09-12
  • 1970-01-01
相关资源
最近更新 更多