Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.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_Multithreading - Fatal编程技术网

Java 用于创建单例实例的工厂方法

Java 用于创建单例实例的工厂方法,java,multithreading,Java,Multithreading,我已经在静态工厂方法中编写了以下代码来返回DefaultCache的单个实例 public static ICache getInstance() { if (cacheInstance == null) { synchronized (ICache.class) { if (cacheInstance == null) { cacheInstance = new DefaultCache(); } }


我已经在静态工厂方法中编写了以下代码来返回DefaultCache的单个实例

public static ICache getInstance() {
   if (cacheInstance == null) {
      synchronized (ICache.class) {
         if (cacheInstance == null) {
            cacheInstance = new DefaultCache();
         }
      }
   }
   return cacheInstance;
}

我们真的需要对同步块内的cacheInstance进行第二次空检查吗?

有一个私有构造函数来避免所有这些检查

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

    private Singleton() {
    }

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

假设 CaseExcase是静态的,则应该考虑两种可能的初始化策略:

  • 惰性初始化:使用实例填充singleton字段 在第一次使用时(如您的示例中)

  • (标准)初始化:singleton字段填充一个 JVM加载类后立即执行

因此,如果您打算使用惰性初始化,您应该检查空值,否则您将只返回空指针

或者,也可以在静态块中初始化字段

//class declaration
 static {   
  cacheInstance = new DefaultCache(); 
 }
或者在你声明的同一行

private static final DefaultCache cacheInstance = new DefaultCache(); 

我将避免使用延迟初始化的单例进行争用检查:

public class Singleton {
    public static ICache getInstance() {
       return LazyCacheInitializer.INSTANCE;
    }

    private class LazyCacheInitializer {
       private static final ICache INSTANCE = new DefaultCache();
    }
}

您需要进行第二次检查,因为在尝试获取锁时,该值可能已由另一个线程设置。事实上,在进入同步块之前,您没有该值的安全视图。它可能是由另一个线程在任何时间之前设置的

最简单的惰性单例是使用枚举

public enum DefaultCache implements ICache {
     INSTANCE
}
我假设您没有这样做,以便可以更改实现


顺便说一句:我建议您只在可能的情况下使用无状态单例,并尽可能对所有有状态对象使用依赖注入。

是的,否则可以创建两个以上的实例。假设您有多个线程。第一个测试是使用races条件完成的,即一些线程同时将变量视为null,并尝试设置实例。如果不进行第二次检查,每个线程将创建一个新实例。

您始终可以使用基于
enum
的单例模式实现,如Peter posted,但请记住,您的所有实现都是单例每个类加载器


您还必须注意
Cloneable
接口。

这比使用
enum
有什么好处?@Peter嗯,enum的缺点是其序列化模型。枚举仅序列化其名称,而不序列化其状态。如果单身汉可以有任何一种状态,它就会丢失。因此,状态为的枚举不能通过网络发送,也不能从磁盘保存和恢复。不确定在这种特殊情况下考虑序列化单例缓存是否有帮助,但您的问题是关于优点/缺点。虽然同意您的观点,但您必须对此代码进行大量更改才能使用反序列化缓存,因此我不确定这是否更好。@Peter可能,但这不是问题,也不是你的问题。简单地说,我的观点是,enums在这方面会遇到麻烦。除了答案之外,还可以看看c2.com/cgi/wiki?SingletonsReeville您可能想阅读维基百科的文章