单例模式实现

单例模式,以及各种实现方式优缺点

恶汉模式

// 恶汉模式
// 在类加载期间初始化静态实例,保证实例的创建是线程安全的.
// 优点: 不支持延迟加载实例(懒加载) , 此中方式类加载比较慢,但是获取实例对象比较快
// 缺点: 该对象足够大的话,而一直没有使用就会造成内存的浪费
public class Singleton_01 {
    // 私有方法,无法通过new方式获取
    private Singleton_01(){
    }

    // static 保证类加载时候创建对象
    // final 保证调用方不会引用其他对象
    private static final Singleton_01 instance = new Singleton_01();
    // 公共的访问方式,供外部访问 获取到单例对象
    public static Singleton_01 getInstance(){
        return instance;
    }
}


// 懒汉式(线程安全)
// 同步静态方法获取单例对象,synchronized保证多线程唯一性以及可见性
// 优点:推迟对象初始化时间点,在需要时候创建单例对象,相比恶汉模式,减少类加载性能开销。同时同步方法保证了多线程场景下单例对象唯一性
// 缺点:每次获取单例对象时会上锁增加性能开销,无论是否已经初始化instance
public class Singleton_03 {
    private Singleton_03(){}

    // static 获取单例对象方法为static修饰
    private static Singleton_03 instance;

    // 方法上添加synchronized,锁对象为当前类class对象
    public static synchronized Singleton_03 getInstance(){
        if(instance == null){
            instance = new Singleton_03();
        }
        return instance;
    }

}

双重校验

// 双重校验
// 优点:推迟对象初始化时间点,在需要时候创建单例对象,相比恶汉模式,减少类加载性能开销。相比 懒汉式(线程安全) 不用每次都获取锁对象减少无意义锁获取造成的性能开销
// 缺点:有序性问题,在调用new创建单例对象时候实际过程为1  .
public class Singleton_04 implements Serializable {
    private Singleton_04(){}

    // volatile: 每次获取单例对象时候检查是否已初始化,因此需要 volatile 修饰
    // static: 获取单例对象方法为静态方法,静态上下文使用的属性需要用static修饰
    private static volatile Singleton_04 instance = null;


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

    // 反射和序列化破坏单例模式
    public static void main(String[] args) throws Exception {
        serialDestroySingleton();
    }

    // 反射破坏单例模式
    public static void refelectionDestroySingleton() throws Exception{
        Class<Singleton_04> clazz = Singleton_04.class;
        Constructor<Singleton_04> constructor = clazz.getDeclaredConstructor();
        constructor.setAccessible(true);
        Singleton_04 obj = constructor.newInstance();
        Singleton_04 obj2 = getInstance();
        System.out.println(obj2 == obj);  // false
    }

    // 序列化破坏单例模式
    public static void serialDestroySingleton() throws Exception{

        Singleton_04 obj2 = getInstance();
        ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("singleton.obj"));
        output.writeObject(obj2);

        // 将序列化对象反序列化,创建对象
        ObjectInputStream input = new ObjectInputStream(new FileInputStream(new File("singleton.obj")));
        Singleton_04 obj  = (Singleton_04)input.readObject();

        System.out.println(obj == obj2 );// false

    }
}

静态内部类实现


// 静态内部类
// 优点:同样做到单例对象延迟初始化,由于是通过类加载方式初始化单例对象,所以没有线程安全问题
// 缺点:通过序列化和反序列化方式可以破坏单例模式
public class Singleton_05 implements Serializable {
    private static class SingletonHolder{
        private static Singleton_05 instance = new Singleton_05();
    }
    private Singleton_05(){
        // 放置通过反射方式多次创建不同单例对象
        if(SingletonHolder.instance != null){
            throw new RuntimeException("不允许非法访问!");
        }
    }

    public static Singleton_05 getInstance(){
        return SingletonHolder.instance;
    }

    // 反射方式破坏单例模式
    public static void fun() throws Exception{
        Class<Singleton_05> clazz = Singleton_05.class;
        Constructor<Singleton_05> constructor = clazz.getDeclaredConstructor();
        constructor.setAccessible(true);
        // 多次创建对象,并且两个单例对象是不同的
        Singleton_05 instance1 = constructor.newInstance();
        Singleton_05 instance2 = constructor.newInstance();
        System.out.println(instance2 == instance1); // false
    }

    // 序列化对单例模式的破坏
    public static void fun2() throws Exception{
        // 将内存中单例对象序列化
        ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("singleton.obj"));
        output.writeObject(getInstance());

        // 将序列化对象反序列化,创建对象
        ObjectInputStream input = new ObjectInputStream(new FileInputStream(new File("singleton.obj")));
        Singleton_05 obj = (Singleton_05)input.readObject();

        // 比较两个对象是否相等
        System.out.println("compare 2 obj");
        System.out.println(obj == obj.getInstance()); // false
    }

    public static void main(String[] args) {
        try {
            fun2();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

枚举实现方式

// 枚举方式
// 优点:由于枚举没有无参构造方法,所以无法通过反射调用构造方法创建实例 ,同时序列化也无法破坏单例模式
public enum Singleton_06 {
    INSTANCE;

    private Object data;

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public static Singleton_06 getInstance(){

        return INSTANCE;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值