java单例的四种实现方式

单例的四种实现方式

一、饿汉方式

public class Singleton{

  private static Singleton instance = new Singleton();

  private Singleton(){}

  public static Singleton getInstance() {
    return instance;
  }
}
  • 优点:代码简单,避免多线程同步问题
  • 缺点:类的初始化阶段就会导致实例化,无法延迟实例化。
触发类进行初始化条件
  1. 使用new关键字创建一个对象
  2. 读取/设置一个类的静态字段
  3. 使用反射调用类
  4. 初始化一个类时候,如果其父类还未被初始化,会优先触发其父类初始化
  5. 当jvm启动时,用于指定执行的主类

二、懒汉方式(DCL)

public class Singleton {

    private static volatile Singleton singleton = null;

    private Singleton(){}

    public static Singleton getSingleton(){
      if(singleton == null){
        synchronized (Singleton.class){
          if(singleton == null){
            singleton = new Singleton();
          }
        }
      }
    return singleton;
   }
}
  • 优点:延迟单例实例化,以DCL方式提高线程并发效率
  • 注意:JDK1.5引入关键字volatile才能达到正常单例效果。对一个volatile域的写,happens- before 于任意后续对这个volatile域的读,即保证了读写操作不会乱序。

参考文献:
http://www.race604.com/java-double-checked-singleton/?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io


三、静态内部类

public class Singleton {

  /**
  * 是静态内部类,该内部类的实例与外部类的实例没有绑定关系,
  * 而且只有被调用到才会装载,从而实现了延迟加载
  */
  private static class SingletonHolder {
    //保证了线程安全
    private static final Singleton INSTANCE = new Singleton();
}

  private Singleton (){}
  
  public static final Singleton getInstance() {    
      return SingletonHolder.INSTANCE;
  }
}
  • 优点1:线程安全——利用了classloader机制保证只有一个线程来初始化类。
  • 优点2:延迟实例化——只有通过getInstance方法才会触发内部类被初始化。

四、枚举

public enum Singleton {

  INSTANCE;

  private String name;

  public String getName(){
    return name;
  }

  public void setName(String name){
    this.name = name;
  }
}

在JDK1.5加入enum特性

使用enum实现单例优点:
  1. 线程安全(构造方法)——无序担心DCL带来的影响
  2. 不因为序列化而产生新实例
  3. 防止反射攻击

参考文献:
https://segmentfault.com/q/1010000000646806

你可能感兴趣的:(java单例的四种实现方式)