单例模式几种安全的实现

单例的应用场景:

需要频繁的创建和销毁对象的、创建对象时耗时过多或者消耗资源过多但是又经常用到的对象、工具类对象或数据库或文件的对象。

当对象含有可改变的状态时(更精确的说就是在实际应用中该状态会改变),则用多例。

一、懒汉式,线程安全的实现

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

这虽然是线程安全的,但是效率低。还有一些比较常犯的错误,不加同步限制的,不做举例。

二、饿汉式,线程安全

1.构造器私有化

2.类的内部创建对象

3.像外部暴露一个静态的公共方法。getInstance

优点:在类装载的时候就完成了实例化。避免了线程同步问题。

缺点:没有达到Lazy Loading(懒加载)的效果,如果从来没使用过这个类,就会造成内存的浪费。

public class Singleton{
  //类加载时就初始化
  private static final Singleton instance = new Singleton();

  private Singleton(){}

  public static Singleton getInstance(){
    return instance;
  }
}

但是要是明确要求是需要懒加载的,这个就不行的

第二种写法,在类的静态代码块中创建实例:

public class Singleton {
    //1.构造函数私有化
    private Singleton() {

    }

    //2.在本类的内部创建对象实例
    private static Singleton instance;

    static {
        instance = new Singleton();
    }

    //3.提供静态方法,返回实例对象
    public static Singleton getInstance() {
        return instance;
    }
}

三、静态内部类

我比较倾向于使用静态内部类的方法,这种方法也是《Effective Java》上所推荐的。

public class Singleton {  
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}

 

四、枚举

用枚举写单例实在太简单了!这也是它最大的优点。下面这段代码就是声明枚举实例的通常做法。

public enum EasySingleton{
INSTANCE;
}

创建enum时,编译器会自动为我们生成一个继承自java.lang.Enum的类,我们上面的enum可以简单看作:

class Type extends Enum{
    public static final Type A;
    public static final Type B;
    ...
}

 demo:

public enum SingleEnum {
    INSTANCE;
    private static String[] strings = {"1", "2"};
    public String[] getStrings() {
        return strings;
    }
}

五、双重检测

//双重检查
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; } }

这个代码只在第一次,两个线程不能同时执行synchronized方法,但是,后面install不为空后,instance == null就直接pass掉了。volatile的作用理解是instance = new Singleton立即到内存中生效。

原文地址:https://www.cnblogs.com/chenmz1995/p/10487026.html