【7.13】单例模式(Singleton)的用法和用处以及破解单例

1):用处  

  是一种创建者模式,只生成一个实例对象,具有全局唯一性,当一个对象的产生需要比较多的资源时, 如读取配置(如数据库连接池、Spring中, 一个Component就只有一个实例Java-Web中, 一个Servlet类只有一个实例等), 产生其他依赖对象, 则可以通过在应用启动时直接产生一个单例对象, 然后永久驻留内存的方式来解决

2):写法

    private化构造函数

    private Singleton实例

    提供一个public的获取实例的方法

  主要有五种实现方式,懒汉式(延迟加载,使用时初始化),饿汉式(声明时初始化),双重检查,静态内部类,枚举

  1:饿汉式

    当多个线程同时访问,都没有实例化的时候,该单例模式将被破坏

public class Singleton {
    private static Singleton instance;
    private Singleton() {
    };
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}  

  2:懒汉式

    线程安全,但是效率低下,多数情况是不需要加锁的

public class Singleton {
    private static Singleton instance;
    private Singleton() {
    };
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}  

  3:双重检查

    

public class Singleton {
    private static volatile Singleton instance;
    private Singleton() {
    };
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}  

  4:匿名内部类

    内部类不会在类的外部被调用,使用当调用暴露的getInstance()方法是调用,由于java虚拟机的classLoaded机制,不会被重复调用使用

public class Singleton {
    private Singleton() {
    };
    public static Singleton getInstance() {
        return Holder.instance;
    }
    private static class Holder{
        private static Singleton instance = new Singleton();
    }
}  

  5:枚举类

    枚举类的构造方法被private,不能创建枚举对象,所以保证了线程安全

public enum Singleton {
    INSTANCE;
    public String error(){
        return "error";
    }
} 

3)破坏

  除了枚举,都可以用反射来破坏单例模式,可以通过反射来获取实例对象

import java.lang.reflect.Constructor;
public class TestCase {
    public void testBreak() throws Exception {
        Class<Singleton> clazz = (Class<Singleton>) Class.forName("Singleton");
        Constructor<Singleton> constructor = clazz.getDeclaredConstructor();
        constructor.setAccessible(true);
        Singleton instance1 = constructor.newInstance();
        Singleton instance2 = constructor.newInstance();
        System.out.println("singleton? " + (instance1 == instance2));
    }
    public static void main(String[] args) throws Exception{
        new TestCase().testBreak();
    }
}  

    

原文地址:https://www.cnblogs.com/yuwenhui/p/7162621.html