我们可以通过哪些不同的方式打破 Java 中的单例模式

新手上路,请多包涵

我们可以通过哪些不同的方式来打破 Java 中的单例模式。我知道一种方法,即如果我们不同步 singleton 中的方法,那么我们可以创建多个类的实例。因此应用了同步。有没有办法打破单例 java 类。

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

原文由 Harsha_2012 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 385
1 个回答

从您给定的代码开始,“双重检查锁定”可能会在某些环境中被破坏,当在使用 Symantec JIT 的系统上运行时,它不起作用。特别是,Symantec JIT 编译

singletons[i].reference = new Singleton();

如下(注意 Symantec JIT 使用基于句柄的对象分配系统)。

 0206106A   mov         eax,0F97E78h
0206106F   call        01F6B210                  ; allocate space for
                                                 ; Singleton, return result in eax
02061074   mov         dword ptr [ebp],eax       ; EBP is &singletons[i].reference
                                                ; store the unconstructed object here.
02061077   mov         ecx,dword ptr [eax]       ; dereference the handle to
                                                 ; get the raw pointer
02061079   mov         dword ptr [ecx],100h      ; Next 4 lines are
0206107F   mov         dword ptr [ecx+4],200h    ; Singleton's inlined constructor
02061086   mov         dword ptr [ecx+8],400h
0206108D   mov         dword ptr [ecx+0Ch],0F84030h

如您所见,对 singletons[i].reference 的赋值是在调用 Singleton 的构造函数之前执行的。这在现有的 Java 内存模型下是完全合法的,在 C 和 C++ 中也是合法的(因为它们都没有内存模型)。

http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

除此之外

  1. 如果类是 Serializable 它可能会中断
  2. 如果它是“可克隆的”,它可能会崩溃
  3. 你可以打破 Reflection (我相信)
  4. 它可以中断 ff 多个类加载器加载类

* 你如何解决违反规则的问题?

  1. 进行急切初始化要安全得多
  2. 为防止反序列化以创建新对象,您可以覆盖类中的 readResolve() 方法并抛出异常
  3. 为防止克隆,您可以 clone() 并抛出 CloneNotSupported 异常
  4. 为了逃避反射实例,我们可以在构造函数中添加检查并抛出异常。

例子

public class Singleton {

    private static final Singleton INSTANCE = new Singleton();

    private Singleton() {
        // Check if we already have an instance
        if (INSTANCE != null) {
           throw new IllegalStateException("Singleton" +
             " instance already created.");
        }
    }
    public static final Singleton getInstance() {
        return INSTANCE;
    }
    private Object readResolve() throws ObjectStreamException         {
            return INSTANCE;
    }
    private Object writeReplace() throws ObjectStreamException {
            return INSTANCE;
    }
    public Object clone() throws CloneNotSupportedException {
        // return INSTANCE
        throw new CloneNotSupportedException();
    }
}


毕竟我建议使用 Enum 作为 Singleton 最安全的方法(因为 java5 最好的方法是使用枚举)

 public static enum SingletonFactory {
    INSTANCE;
    public static SingletonFactory getInstance() {
        return INSTANCE;
    }
}

原文由 Satheesh Cheveri 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题