在Java中,打破单例模式的不同方式有哪些

在Java中,打破单例模式的不同方式有哪些,java,singleton,Java,Singleton,在Java中,有哪些不同的方法可以打破单例模式。 我知道一种方法,即如果我们不在singleton中同步该方法,那么我们可以创建多个类的实例。因此,应用了同步。有没有办法打破单例java类 public class Singleton { private static Singleton singleInstance; private Singleton() { } public static Singleton getSingleInstance() {

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

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

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


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

好吧,有两种方法可以打破它

  • 使用反射

  • 当有自定义类加载器时,不止一个(即父类加载器)。所有单例都应由公共父类加载器加载


首先需要注意的是:在这种情况下,最好是使整个
getSingleInstance(){}
同步化

public synchronized static Singleton getSingleInstance() {
    if (singleInstance == null) {
        singleInstance = new Singleton();
    }
    return singleInstance;
}
除此之外,我认为破解密码并不容易。当然,如果添加递归调用,则可能会中断它,如下所示:

  • 调用此
    单例
    构造函数中其他类的构造函数
  • 在该类的构造函数中,尝试获取这个
    Singleton
    实例

但这是我能想到的唯一一件事,在
单例
类中,你无法保护自己不受此影响。

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

singletons[i].reference = new Singleton();
请注意,Symantec JIT使用基于句柄的对象分配系统

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

除此之外

  • 如果类
    可序列化
  • 如果它是“可关闭的”,它可能会断裂`
  • 你可以通过
    反射
    (我相信)
  • 它可以在类中加载多个类加载器时中断

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

  • 进行快速初始化要安全得多
  • 防止反序列化以创建新对象 您可以重写类中的
    readResolve()
    方法并引发异常
  • 为了防止克隆, 您可以超越
    clone()
    并抛出
    CloneNotSupported
    异常
  • 为了转义反射实例,我们可以在构造函数中添加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();
        }
    }
    

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


    一种方法是序列化。如果未实现readResolve,则使用ObjectInputStream.readObject()读取单例将返回此单例的新实例。

    实际上,不需要同步的安全版本是:

    其他安全版本包括:

    所有这些版本都有优点和缺点,但它们都不需要显式同步,因为它们都依赖于类加载器及其内置线程安全性


    正如其他人所写,您可以通过反序列化来打破其中的一些模式。阅读Joshua Bloch的《有效Java》(第74至78项)中有关防止此类攻击的内容(enum singleton模式是安全的,可以随时抵御此类攻击)。

    同步方法将起作用,但也会减慢对singleton的每次访问,以保护仅在第一次访问中发生的某些事情

    最简单和最安全的方法就是进行快速初始化,这总是安全的,因为Java保证在允许任何人访问之前设置所有成员变量

    public class Singleton {
        private static Singleton singleInstance = new Singleton();
    
        private Singleton() {
        }
    
        public static Singleton getSingleInstance() {
            return singleInstance;
        }
    }
    

    即使使用同步循环,您当前的方法实际上也是失败的——因为双重检查锁定被破坏了。如果要将singleton变量用于双重检查锁定,则需要将其标记为volatile,否则线程仍然可以访问未完全初始化的对象。有关更多详细信息,请参阅。

    假设您已将Singleton类实现为“SingletonPattern”,如下所示。 包com.example.pattern

    public class SingletonPattern
    {
      private static SingletonPattern pattern;
    
      public static SingletonPattern getInstance()
      {
        if (pattern == null)
        {
          synchronized (SingletonPattern.class)
          {
            if (pattern == null)
            {
              pattern = new SingletonPattern();
            }
          }
        }
        return pattern;
      }
    }
    
    现在,您可以使用以下方法打破这个类的单例行为

    Class c = Class.forName("com.example.pattern.SingletonPattern");
    System.out.println((SingltonPattern) c.newInstance());
    
    **单重试验**

    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    /***
     * 
     * Ways to break Singleton
     */
    public class Main {
    
    private static ObjectInputStream inputStream;
    
    public static void main(String[] args) throws Exception {
        Singleton orginalSingletonObject = Singleton.getInstance();
    
        /***
         * Singleton is broken by using Reflection
         */
        breakSingletonByReflection(orginalSingletonObject);
    
        /***
         * By Serialization/De-Serialization break Singleton We need
         * Serialization interface in a class nedds to be serialized like
         * Singleton.java
         */
        breakSingletonByserialization(orginalSingletonObject);
    
        /***
         * By Cloning break Singleton
         * We need to implement Cloneable interface
         */
        breakSingletonByCloning(orginalSingletonObject);
    
    
        /***
         * Break Singleton By thread
         * This scenario is related to multi-threading environment
         * 
         */
    
        breakSingletonByThreading(orginalSingletonObject);
    }
    
    private static void breakSingletonByThreading(Singleton orginalSingletonObject) {
    
        ExecutorService executorService=Executors.newFixedThreadPool(2);
        /**
         * Run this code snippet after commenting the other code for better understanding
         * Run it repeatly to create a condition when 2 threads enter the method getInstance() of Singleton class at a same time 
         * When 2 threads enter the getInstance method at same time they will get the singleton object as null (private static Singleton singleton in Singleton.java)
         * Then they will create two different objects ( have different hashcode) in this case singleton pattern will break.
         */
        executorService.submit(Main::useSingleton); // JAVA 8 syntax it will get the singleton instance
        executorService.submit(Main::useSingleton);
        executorService.shutdown();
    }
    
    public static void useSingleton(){
        Singleton singleton=Singleton.getInstance();
        printSingletonData("By Threading", singleton);
    
    }
    
    
    private static void breakSingletonByCloning(Singleton orginalSingletonObject) throws CloneNotSupportedException {
        Singleton clonedSingletonObject=(Singleton) orginalSingletonObject.clone();
        printSingletonData("By Cloning", orginalSingletonObject, clonedSingletonObject);
    }
    
    private static void breakSingletonByReflection(Singleton orginalsingleton)
            throws ClassNotFoundException, NoSuchMethodException,
            InstantiationException, IllegalAccessException,
            InvocationTargetException {
    
        Class<?> singletonClass = Class.forName("SingletonTest.Singleton");
        @SuppressWarnings("unchecked")
        Constructor<Singleton> constructor = (Constructor<Singleton>) singletonClass
                .getDeclaredConstructor();
        constructor.setAccessible(true);
        Singleton s = constructor.newInstance();
        printSingletonData("By Reflection", orginalsingleton, s);
    }
    
    private static void breakSingletonByserialization(Singleton orginalsingleton)
            throws FileNotFoundException, IOException, ClassNotFoundException {
    
        /**
         * Serialization
         */
        ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("E:\\Singleton.ser"));
        outputStream.writeObject(orginalsingleton);
        outputStream.close();
    
        /**
         * DeSerialization
         */
        inputStream = new ObjectInputStream(new FileInputStream("E:\\Singleton.ser"));
    
        Singleton deserializeObject = (Singleton) inputStream.readObject();
        deserializeObject.hashCode();
        printSingletonData("By Serialization", orginalsingleton, deserializeObject);
    
    
    }
    
    public static void printSingletonData(String operationName,
            Singleton orginalsingleton, Singleton reflectionSigletonObject) {
    
        System.out.println("------------------------------------------");
        System.out.println("New Operation");
        System.out.println(operationName);
        System.out.println("orginal Hashcode=" + orginalsingleton.hashCode());
        System.out.println("New Object hashcode="
                + reflectionSigletonObject.hashCode());
        Boolean value = orginalsingleton.hashCode() != reflectionSigletonObject.hashCode();
        System.out.println("These Object have different hascode. They are two different object Right = "
                        + value);
        System.out.println("As these are different Object this means Singleton Pattern is broken");
    }
    
    
    private static void printSingletonData(String operationName,Singleton singleton) {
    
    
        System.out.println("------------------------------------------");
        System.out.println("New Operation");
        System.out.println(operationName);
        System.out.println("Object hashcode="   + singleton.hashCode());
    
    }
    }
    
    import java.io.FileInputStream;
    导入java.io.FileNotFoundException;
    导入java.io.FileOutputStream;
    导入java.io.IOException;
    导入java.io.ObjectInputStream;
    导入java.io.ObjectOutputStream;
    导入java.lang.reflect.Constructor;
    导入java.lang.reflect.InvocationTargetException;
    导入java.util.concurrent.ExecutorService;
    导入java.util.concurrent.Executors;
    /***
    * 
    *打破单身的方法
    */
    公共班机{
    私有静态对象inputStream inputStream;
    公共静态void main(字符串[]args)引发异常{
    Singleton orginalSingletonObject=Singleton.getInstance();
    /***
    *Singleton是通过使用反射来打破的
    */
    breakSingletonByReflection(原始SingleTonObject);
    /***
    *通过序列化/反序列化打破我们需要的单例
    *类中要序列化的序列化接口,如
    *Singleton.java
    */
    breakSingletonByserialization(orginalSingletonObject);
    /***
    *通过克隆打破单身
    *我们需要实现克隆
    
    public enum Singleton{
        INSTANCE;
    }
    
    public class Singleton {
        private static Singleton singleInstance = new Singleton();
    
        private Singleton() {
        }
    
        public static Singleton getSingleInstance() {
            return singleInstance;
        }
    }
    
    public class SingletonPattern
    {
      private static SingletonPattern pattern;
    
      public static SingletonPattern getInstance()
      {
        if (pattern == null)
        {
          synchronized (SingletonPattern.class)
          {
            if (pattern == null)
            {
              pattern = new SingletonPattern();
            }
          }
        }
        return pattern;
      }
    }
    
    Class c = Class.forName("com.example.pattern.SingletonPattern");
    System.out.println((SingltonPattern) c.newInstance());
    
    import java.io.Serializable;
    
    public class Singleton implements Serializable,Cloneable{
    
    private static final long serialVersionUID = 1L;
    
    private static Singleton singleton=null;
    private Singleton(){
    
    }
    
    public static Singleton getInstance(){
        if(singleton==null){
            singleton=new Singleton();
        }
        return singleton;   
    }
    
    @Override
    public Object clone() throws CloneNotSupportedException{
        return super.clone();
    }
    }
    
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    /***
     * 
     * Ways to break Singleton
     */
    public class Main {
    
    private static ObjectInputStream inputStream;
    
    public static void main(String[] args) throws Exception {
        Singleton orginalSingletonObject = Singleton.getInstance();
    
        /***
         * Singleton is broken by using Reflection
         */
        breakSingletonByReflection(orginalSingletonObject);
    
        /***
         * By Serialization/De-Serialization break Singleton We need
         * Serialization interface in a class nedds to be serialized like
         * Singleton.java
         */
        breakSingletonByserialization(orginalSingletonObject);
    
        /***
         * By Cloning break Singleton
         * We need to implement Cloneable interface
         */
        breakSingletonByCloning(orginalSingletonObject);
    
    
        /***
         * Break Singleton By thread
         * This scenario is related to multi-threading environment
         * 
         */
    
        breakSingletonByThreading(orginalSingletonObject);
    }
    
    private static void breakSingletonByThreading(Singleton orginalSingletonObject) {
    
        ExecutorService executorService=Executors.newFixedThreadPool(2);
        /**
         * Run this code snippet after commenting the other code for better understanding
         * Run it repeatly to create a condition when 2 threads enter the method getInstance() of Singleton class at a same time 
         * When 2 threads enter the getInstance method at same time they will get the singleton object as null (private static Singleton singleton in Singleton.java)
         * Then they will create two different objects ( have different hashcode) in this case singleton pattern will break.
         */
        executorService.submit(Main::useSingleton); // JAVA 8 syntax it will get the singleton instance
        executorService.submit(Main::useSingleton);
        executorService.shutdown();
    }
    
    public static void useSingleton(){
        Singleton singleton=Singleton.getInstance();
        printSingletonData("By Threading", singleton);
    
    }
    
    
    private static void breakSingletonByCloning(Singleton orginalSingletonObject) throws CloneNotSupportedException {
        Singleton clonedSingletonObject=(Singleton) orginalSingletonObject.clone();
        printSingletonData("By Cloning", orginalSingletonObject, clonedSingletonObject);
    }
    
    private static void breakSingletonByReflection(Singleton orginalsingleton)
            throws ClassNotFoundException, NoSuchMethodException,
            InstantiationException, IllegalAccessException,
            InvocationTargetException {
    
        Class<?> singletonClass = Class.forName("SingletonTest.Singleton");
        @SuppressWarnings("unchecked")
        Constructor<Singleton> constructor = (Constructor<Singleton>) singletonClass
                .getDeclaredConstructor();
        constructor.setAccessible(true);
        Singleton s = constructor.newInstance();
        printSingletonData("By Reflection", orginalsingleton, s);
    }
    
    private static void breakSingletonByserialization(Singleton orginalsingleton)
            throws FileNotFoundException, IOException, ClassNotFoundException {
    
        /**
         * Serialization
         */
        ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("E:\\Singleton.ser"));
        outputStream.writeObject(orginalsingleton);
        outputStream.close();
    
        /**
         * DeSerialization
         */
        inputStream = new ObjectInputStream(new FileInputStream("E:\\Singleton.ser"));
    
        Singleton deserializeObject = (Singleton) inputStream.readObject();
        deserializeObject.hashCode();
        printSingletonData("By Serialization", orginalsingleton, deserializeObject);
    
    
    }
    
    public static void printSingletonData(String operationName,
            Singleton orginalsingleton, Singleton reflectionSigletonObject) {
    
        System.out.println("------------------------------------------");
        System.out.println("New Operation");
        System.out.println(operationName);
        System.out.println("orginal Hashcode=" + orginalsingleton.hashCode());
        System.out.println("New Object hashcode="
                + reflectionSigletonObject.hashCode());
        Boolean value = orginalsingleton.hashCode() != reflectionSigletonObject.hashCode();
        System.out.println("These Object have different hascode. They are two different object Right = "
                        + value);
        System.out.println("As these are different Object this means Singleton Pattern is broken");
    }
    
    
    private static void printSingletonData(String operationName,Singleton singleton) {
    
    
        System.out.println("------------------------------------------");
        System.out.println("New Operation");
        System.out.println(operationName);
        System.out.println("Object hashcode="   + singleton.hashCode());
    
    }
    }
    
        Constructor constructor = cls.getDeclaredConstructor();
        constructor.setAccessible(true);
    
        Singleton singleton = (Singleton) constructor.newInstance();