Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/352.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 将对象变为单例?_Java_Design Patterns_Singleton - Fatal编程技术网

Java 将对象变为单例?

Java 将对象变为单例?,java,design-patterns,singleton,Java,Design Patterns,Singleton,我不确定以前是否有人问过这个问题(如果有,我道歉) 从维基百科复制的代码 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 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标准库类,那么上面的“singleton”线程是安全的。

第一个示例是安全的,因为没有可变状态

在第二个示例中,singleton没有做任何事情使其线程安全,它是否安全取决于
FancyClass
是否是线程安全的。将
synchronized
放在
doSomething
方法上会使其线程安全


obj1
obj2
引入getter和setter也可能会产生问题,这些问题必须与
doSomething
方法在同一个锁上同步,即使
FancyClass
是线程安全的,也需要锁定,因为如果不同的线程正在更改内容,那么这些更改需要在线程之间可见

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


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

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

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

doSomething()
方法不是线程安全的。如果您需要原子操作,请将其同步。

关于您的代码-
由于您将构造函数设置为私有,因此永远不会调用它。所以宣布它为空是没有意义的。无论如何,实例变量都会自动指定默认值

首先是第一个代码

   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;
  }

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

好的,根据文档,FancyClass是线程安全的。(JDK的一部分)由于您将构造函数设置为私有,因此永远不会调用它。所以宣布它为空是没有意义的。无论如何,实例变量是自动分配的默认值。@AniketThakur是的,这是超级愚蠢的(在构造函数中初始化为null)。我只是在没有细节的情况下重写了一个现有的类。注意,在中插入一个
synchronized
,不会使需要多个方法调用的操作线程安全。同步的
“get”方法通常是没有意义的。(ObComment:Mutable statics是一个非常糟糕的主意。)您忘记了将其设置为volatile它应该是:private static volatile Singleton singleInstance=null;为什么你需要检查相同的东西。“我想这是个错误吗?”安德烈·马汀不,这不是个错误。它被称为双重锁定机构。这是@AniketThakur:谢谢-以前从未见过。将对此进行阅读。@AndresL Yes线程调度期间可能会出现问题。因此,将其声明为volatile也是一种很好的做法。谢谢你指出。我想obj1和obj2的getter和setter也是如此,我也需要使它们同步?@fedvasu如果你只设置或获取对象,那么同步就没有必要了。见: