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如果你只设置或获取对象,那么同步就没有必要了。见: