【23种设计模式】-单例模式

什么是单例模式?

保证一个类只有一个实例,并且提供一个访问该实例的全局访问点

如何保证一个类只有一个实例?

1)将构造方法设置为私有的,无法实例化

2)将方法设置为static

如何提供一个全局访问点?

设置一个get方法获取实例

常见的五种单例模式实现方式:

1.饿汉式(线程安全,调用效率高,不能延迟加载)

缺点:类一初始化,内存空间就已开辟,当没调用该类时,造成空间的浪费

/**
 * 饿汉式单例
 */
public class SingletonDemo01 {
    //私有构造方法
    private SingletonDemo01() {
    }
    //设置为static,类初始化立即加载该对象
    private static SingletonDemo01 instance = new SingletonDemo01();

    //获取实例,没有synchronized,效率高
    public static SingletonDemo01 getInstance() {
        return instance;
    }

}

class  SingleTonTest01{
    public static void main(String[] args) {
        SingletonDemo01 instance01 = SingletonDemo01.getInstance();
        SingletonDemo01 instance02 = SingletonDemo01.getInstance();
        System.out.println(instance01 == instance02);  //返回true,代表同一个对象
    }
}

2.懒汉式(线程安全,调用效率不高,可以延迟加载)

为了解决第一种单例模式的的缺点,将上面的代码加以改进形成了懒汉式模型

但是这种实现方式还是有缺点的,获取该对象的方法增加了synchronized方法,所以效率较低,为了解决这一问题,继续改进

/**
 * 懒汉式单例
 */
public class SingletonDemo02 {
    //私有构造方法
    private SingletonDemo02() {
    }

    //定义一个对象,类初始化时,不立即加载该对象
    private static SingletonDemo02 instance;

    //获取实例,增加synchronized,效率较低!
    public static synchronized SingletonDemo02 getInstance() {
        if (instance == null) {
            instance = new SingletonDemo02();
        }
        return instance;

    }

}

class SingleTonTest02 {
    public static void main(String[] args) {
        SingletonDemo02 instance01 = SingletonDemo02.getInstance();
        SingletonDemo02 instance02 = SingletonDemo02.getInstance();
        System.out.println(instance01 == instance02);  //返回true,代表同一个对象
    }
}

3.DCL懒汉式(双重检测)

优点:效率提高

缺点:非原子性,极端情况下会存在破坏对象创建的问题

/**
 * DCL懒汉式单例(双重检测)
 */
public class SingletonDemo03 {
    //私有构造方法
    private SingletonDemo03() {
    }

    //定义一个对象,类初始化时,不立即加载该对象
    private static volatile SingletonDemo03 instance;

    //获取对象
    public static SingletonDemo03 getInstance() {
        if (instance == null) {
            //第一次实例化时 进行synchronized,下次再使用时直接获取已创建好的对象
            synchronized (SingletonDemo03.class) {
                if (instance == null) {
                    instance = new SingletonDemo03();
                }
            }
        }
        return instance;

    }

}

class SingleTonTest03 {
    public static void main(String[] args) {
        SingletonDemo03 instance01 = SingletonDemo03.getInstance();
        SingletonDemo03 instance02 = SingletonDemo03.getInstance();
        System.out.println(instance01 == instance02);  //返回true,代表同一个对象
    }
}

4.饿汉式改进(静态内部类实现)

为了改进上一种实现的缺点,将实例化对象添加到静态内部类中

缺点:如果利用反射机制可以破坏私有构造方法,将私有权限忽略,导致可以直接实例化。

/**
 * 静态内部类实现
 */
public class SingletonDemo04 {
    //私有构造方法
    private SingletonDemo04() {
    }

    //静态内部类实例化对象
    private static class InnerClass {
        private static final SingletonDemo04 instance = new SingletonDemo04();
    }

    //get方法获取内部类中的对象
    public static SingletonDemo04 getInstance() {
        return InnerClass.instance;
    }

}

class SingleTonTest04 {
    public static void main(String[] args) {
        SingletonDemo04 instance01 = SingletonDemo04.getInstance();
        SingletonDemo04 instance02 = SingletonDemo04.getInstance();
        System.out.println(instance01 == instance02);  //返回true,代表同一个对象
    }
}

5.枚举单例

为了解决反射机制破坏私有构造方法这个问题,继续改进,使用枚举单例

优点:可以有效规避反射方式破坏类的结构

/**
 * 枚举类型单例模式
 */
public enum SingletonDemo05 {
    INSTANCE;

    public SingletonDemo05 getInstance() {
        return INSTANCE;
    }
}

class SingleTonTest05 {
    public static void main(String[] args) {
        SingletonDemo05 instance01 = SingletonDemo05.INSTANCE;
        SingletonDemo05 instance02 = SingletonDemo05.INSTANCE;
        System.out.println(instance01 == instance02);  //返回true,代表同一个对象
    }
}

猜你喜欢

转载自blog.csdn.net/java_cxrs/article/details/104736703