在java中使用不可变类的单例

Try*_*ing 3 java concurrency

class MyClass
{
  private static volatile Resource resource;

  public static Resource getInstance()
  {
            if(resource == null)
                      resource = new Resource();
            return resource;
  }
}
Run Code Online (Sandbox Code Playgroud)

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

Jef*_*rey 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.
Run Code Online (Sandbox Code Playgroud)

它现在已经初始化了两次,而不是单身.

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

  1. 使getInstance方法同步

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

您也不需要将变量设置为volatile.在#1的情况下,同步方法仍会刷新变量,因此所有变量都将看到更新的副本.在#2的情况下,保证对象在构造之后对所有对象可见.