java - 使用 static volatile 与 static 时的实例数

标签 java multithreading

我读到this文章声称在 java 1.5 中使用静态成员是线程安全的。这是否也意味着该成员只有一个实例,或者不同的线程可以缓存不同的实例?

例如:

public class MyClass {
 private static Foo foo = null;

 public String getFoo()
 {
     if (foo== null)
        foo= new Foo();
     //init foo...
  }
}

如果我有几个线程这样做:

String foo = (new MyClass()).getFoo();

我猜所有线程都会得到相同的“init”foo,但是foo会被init多少次?如果我添加 volatile 并将 foo 定义为“public static volatile Foo...”,它会改变什么吗?

最佳答案

I read this article which claim using static member with java 1.5 is thread safe.

更具体地说,Java Memory Model FAQ具体说:

If a field is set in a static initializer, it is guaranteed to be made visible, correctly, to any thread that accesses that class

在您发布的代码中,您的 static 字段在静态初始值设定项中设置。如果它执行以下操作,则不会出现线程安全问题:

private static Foo foo = new Foo();

但是,在大多数其他情况下,使用 static 字段时,线程安全是一个问题:

In other words, do not place a reference to the object being constructed anywhere where another thread might be able to see it; do not assign it to a static field, do not register it as a listener with any other object, and so on.

您的其他问题:

I guess that all threads will get same "init" Foo

对此没有任何保证。两个线程可以同时调用 getFoo() 并肯定会获取 Foo 的不同实例。

but how many times foo will be init?

这是未知的,取决于正在运行的线程数、数据发布等。

what if I'll add volatile and define foo as "public static volatile Foo..." will it change anything?

它将确保至少 Foo 在分配给静态字段时能够正确构造,但它绝不会再次保护您在多个线程调用 时发生的竞争条件同时调用 getFoo()

通常,当 Foo 的构造很便宜并且我不介意其中一个线程使用其 实例时,我会使用 volatile 静态 字段模式code>Foo 然后它被垃圾收集。我只是希望其余大部分操作使用同一个实例。

另一种模式是执行如下操作:

private static final AtomicReference<Foo> fooRef = new AtomicReference<Foo>();

public static String getFoo() {
   Foo foo = fooRef.get();
   if (foo != null) {
      return foo;
   }
   foo = new Foo();
   if (fooRef.compareAndSet(null, foo)) {
      return foo;
   } else {
      // foo ref was set by another thread so our Foo is not used
      return fooRef.get();
   }
}

这可能会创建然后丢弃几个额外的 Foo 实例,但至少所有线程都会使用相同的 Foo 实例。

但是,如果必须有且仅有一个 Foo 实例,并且您无法在静态初始值设定项中构造它(参见上文),那么您将被迫锁定其实例施工。

关于java - 使用 static volatile 与 static 时的实例数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22213087/

相关文章:

java - 如何从 LinkedList pp = new LinkedList(); 中删除整数?

java - 从 Firebase 检索一些数据并将其放在 RecyclerView 上

Java Eclipse 求值表达式

java - 如何确保打印偶数奇数的两个线程在此实现中保持先偶后奇的顺序?

java - Swing:区分用户引起的组件大小调整和自动组件大小调整的问题(编写自定义布局管理器)

python - 多个线程在 Python 中写入同一个 CSV

java - 在 Java 中的多态数组对象上运行方法时出现问题

java - Eclipse 插件的堆栈跟踪

c++ - 在 pthreads 中指定线程堆栈大小

ios - 计算属性 - 如何仅在主线程上使用?