3
class MyClass
{
  private static volatile Resource resource;

  public static Resource getInstance()
  {
            if(resource == null)
                      resource = new Resource();
            return resource;
  }
}

这里如果Resource是一个不可变的类,那么写上面的代码安全吗?正如在实践中的 java 并发中提到的那样,“初始化安全允许正确构造的不可变对象在线程之间安全地共享。所以上面的代码可以安全地编写。” (在第 349 16.3 页)。但是有了这个,如果两个线程检查空值并且它们可以继续创建对象,这是可能的,这违反了类的不变量(单例)。请解释。链接中问题的延续

4

1 回答 1

6

不,这不是线程安全代码。在这种情况下,Resource可能是线程安全的,但您的getInstance方法不是。

想象一下这一系列事件

Thread1 calls getInstance and checks "if resource == null" and then stops (because the OS said it was time for it to be done) before initializing the resources.

Thread2 calls getInstance and checks "if resource == null" and then initializes the instance

Now Thread1 starts again and it also initializes the instance.

它现在已经被初始化了两次并且不是一个单例。

您有几个选项可以使其线程安全。

  1. 使getInstance方法同步

  2. 在声明时(或在静态初始化器中)初始化实例,并且getInstance可以返回它。

您也不需要使变量易变。在情况 #1 中,同步方法无论如何都会刷新变量,因此所有变量都会看到更新的副本。在情况 #2 中,保证对象在构造后对所有对象可见。

于 2013-02-26T00:32:16.990 回答