单例设计模式-java

154 阅读3分钟

单例设计模式:一个类只能创建一个对象。

单例设计模式的分类:

1、饿汉式:类被加载的时候,对象就被创建出来。

2、懒汉式:类被加载对象不会创建,而是第一次使用对象时被创建。

饿汉式1:静态变量实现

/**
 * instance对象是随着类的加载而创建的。如果该对象足够大的话,而一直没有使用就会造成内存浪费
 * 多线程情况下是安全的
 */
public class Singleton {
    // 1、私有构造器
    private Singleton(){}

    // 2、成员位置声明对象
    private static Singleton instance = new Singleton();

    // 3、暴露访问接口
    public static Singleton getInstance(){
        return instance;
    }
}

饿汉式2:静态代码块实现

/**
 * 该方式也是随着类加载创建对象,所有和方式1一样也存在内存浪费问题
 * 多线程情况下是安全的
 */
public class Singleton {
    // 1、构造器私有化
    private Singleton(){}

    // 2、成员位置声明对象
    private static Singleton instance;

    // 3、静态代码块中创建对象
    static {
        instance = new Singleton();
    }

    // 4、暴露访问接口
    public static Singleton getInstance() {
        return instance;
    }
}

懒汉式1:线程不安全

/**
 * 当调用getInstance()方法获取Singleton类的对象的时
 * 候才创建Singleton类的对象,这样就实现了懒加载的效果。但是,如果是多线程环境,会出现
 * 线程安全问题。
 */
public class Singleton {
    // 1、私有构造器
    private Singleton(){}

    // 2、成员位置声明对象
    private static Singleton instance;

    // 3、暴露访问接口
    public static Singleton getInstance() {
        // 如果对象等于null,则创建对象
        if(instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

懒汉式2:线程安全

/**
 * synchronized关键字,导致getInstance()方法的执行效果特别低。
 * 因为锁把其他线程挡在方法外边,而这个例子中只会在创建对象时(instance = new Singleton();)引发线程安全,
 * 所以可以使用懒汉式3(下一个例子进行优化)
 */
public class Singleton {
    // 私有构造器
    private Singleton(){}

    // 成员位置声明对象
    private static Singleton instance;

    // 暴露访问接口
    public static synchronized Singleton getInstance() {
        // 如果对象等于null,则创建对象
        if(instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

懒汉式3:双重检查锁

/**
 *  添加volatile 关键字之后的双重检查锁模式是一种比较好的单例实现模式,能够保证在多线程
 * 的情况下线程安全也不会有性能问题。
 */
public class Singleton {
    // 私有构造器
    private Singleton(){}

    // 成员位置声明对象
    private static volatile Singleton instance;

    // 暴露访问接口
    public static Singleton getInstance() {
        //第一次判断,如果instance不为null,不进入抢锁阶段,直接返回实际
        if(instance == null) {
            synchronized (Singleton.class) {
                //抢到锁之后再次判断是否为null
                if(instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

饿汉式4:静态内部类

/**
 * 静态内部类单例模式中实例由内部类创建,由于 JVM 在加载外部类的过程中, 是不会加载静态
 * 内部类的, 只有内部类的属性/方法被调用时才会被加载, 并初始化其静态属性。静态属性由于被
 * static 修饰,保证只被实例化一次,并且严格保证实例化顺序。
 */
public class Singleton {
    //私有构造方法
    private Singleton() {}
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }
    //对外提供静态方法获取该对象
    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

枚举方式

public enum Singleton { INSTANCE; }