我们可以在Java中打破单例模式的不同方法有哪些

Har*_*012 11 java singleton

我们可以在Java中打破单例模式的不同方法有哪些.我知道一种方式,即如果我们不在单例中同步方法,那么我们可以创建多个类的实例.因此应用同步.有没有办法打破单例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;
    }
}
Run Code Online (Sandbox Code Playgroud)

Sat*_*eri 10

从您给定的代码开始,"Double-Checked Locking"可能会在某些环境中被破坏,当使用Symantec JIT在系统上运行时,它不起作用.特别是Symantec JIT编译

singletons[i].reference = new Singleton();
Run Code Online (Sandbox Code Playgroud)

以下(注意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
Run Code Online (Sandbox Code Playgroud)

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

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

除此之外

  1. 如果上课,它可以打破 Serializable
  2. 如果它的'Clonable`它可以打破
  3. 你可以突破Reflection(我相信)
  4. 它可以打破ff多个类加载器加载类

*你如何解决违规者?

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

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

public static enum SingletonFactory {
    INSTANCE;
    public static SingletonFactory getInstance() {
        return INSTANCE;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 你可以通过`if(singleInstance!= null)在构造函数中抛出新的RuntimeError();` (2认同)

Dyl*_*eus 0

多线程是单例的最大问题。您可以通过同步或使用急切初始化来避免这种情况。

另一种方法是在不应该使用的地方使用单例。通过使用单例模式,您可能会以阻碍程序后续开发的方式应用它。(例如,在游戏中创建一个单例“玩家”,因为您假设它是单人游戏。开发的下一步“添加合作功能”)。

单例模式有它的优点,但不要在没有仔细考虑的情况下使用它。