2

我不确定,之前是否有人问过这个问题(如果是这样道歉)。

从维基百科复制的代码。

public class Singleton {
   private static final Singleton instance = new Singleton();

   private Singleton() {}

   public static Singleton getInstance() {
      return instance;
   }
}

它是如何线程安全的?是(仅)因为此类中没有变异状态吗?

如果我这样修改会发生什么

public class Singleton {
    private static final Singleton instance = new Singleton();
    private FancyClass obj1;
    private FancyClass obj2;

    //feel free to imagine all the getters and setters for obj1 and obj2,
    // like getObj1() and so forth

    //tricky method
    public void doSomething() {
      obj1.destroyEnemy();
      obj2.destroyFriend();
    }

    private Singleton() {
       obj1 = null;
       obj2 = null;
    }

    public static Singleton getInstance() {
      return instance;
    }
}

我对设计模式讨论没有兴趣,这是我应该维护的那种代码。上面的“单例”线程是安全的,假设 FancyClass 是 java 标准库类。

4

4 回答 4

3

第一个代码保证所有调用的线程都getInstance()获得对同一实例的引用Singleton

obj1对于您的实现(第二个示例), and也是如此obj2,因为它们是在创建类本身时创建的,并且类创建是线程安全的(不能在同一个类加载器中创建两次/“并行”)。

doSomething()方法不是线程安全的。synchronized如果您需要原子操作,请制作它。

于 2013-05-22T14:10:43.240 回答
3

你是对的,第一个例子是安全的,只是因为没有可变状态。

在第二个示例中,单例没有做任何事情来使其成为线程安全的,它是否安全取决于是否FancyClass是线程安全的。使用synchronizeddoSomething方法将使其成为线程安全的。

引入 getter 和 setterobj1并且obj2也有可能产生问题,它们必须在与doSomething方法相同的锁上同步,即使FancyClass是线程安全的,您也需要锁定,因为如果不同的线程正在更改事物,那么这些更改需要跨线程可见。

于 2013-05-22T14:06:48.757 回答
1

单例模式根本不是为了线程安全而设计的,只是为了独特并禁止创建额外的实例。代码中唯一线程安全的部分是 Singleton 实例化private static final Singleton instance = new Singleton();,因为它在类加载时间被调用一次。

但实际上,如果您的类中没有成员被外部系统同时调用的方法修改,您的单例将/保持线程安全

于 2013-05-22T14:08:11.407 回答
0

关于您的代码 - 由于您将构造函数设为私有,因此永远不会调用它。因此,将其声明为 null 没有任何意义。无论如何,实例变量都会自动分配默认值。

首先是第一个代码

   public class Singleton {
   private static final Singleton instance = new Singleton();

   private Singleton() {}

   public static Singleton getInstance() {
      return instance;
   }
}

与延迟初始化不同的是,它被称为早期初始化,在延迟初始化中,您仅在需要时创建实例。为了使其线程安全,您需要执行以下操作

public class Singleton {
  private static Singleton singleInstance;
    private Singleton() {}
  public static Singleton getSingleInstance() {
    if (singleInstance == null) {
      synchronized (Singleton.class) {
        if (singleInstance == null) {
          singleInstance = new Singleton();
        }
      }
    }
    return singleInstance;
  }

示例是延迟初始化,但概念保持不变。

于 2013-05-22T14:12:16.853 回答