单例模式singleTon的几种常见写法 - Java实现

饿汉式:

public class Singleton{
  public static final Singleton INSTANCE = new Singleton();  
  // 注意将默认的无参构造方法访问权限符置为private,防止外部调用该构造方法会new出更多对象实例
  private Singleton(){}

  public static Singleton getInstance(){
    return INSTANCE;
  }

}

单例实现缺点:

  • 如果构造方法存在过多的处理,会导致加载这个类很慢,可能会引起性能问题
  • 在未调用getInstance方法时,JVM也会在加载Singleton类时候去实例化静态字段的INSTANCE,造成内存资源的浪费

懒汉式:

public class Singleton{
  public static Singleton INSTANCE;  
  // 注意将默认的无参构造方法访问权限符置为private,防止外部调用该构造方法会new出更多对象实例
  private Singleton(){}

/**
  多线程情况下,会出现生成多个实例对象问题,导致单例失效
**/
  public static Singleton getInstance_1(){
    if(INSTANCE == null){
      INSTANCE = new Singleton();
    }
    return INSTANCE;
  }

/**
   加上synchronized实现线程同步,可解决多线程情况下单例失效问题,但是考虑到getInstance()方法是一个被频繁调用的方法,这时候会出现性能下降问题,一般不推荐使用这种实现单例的方式
*/
public static synchronized Singleton getInstance_2(){
    if(INSTANCE == null){
      INSTANCE = new Singleton();
    }
    return INSTANCE;
  }

}

双重检查加锁模式(DCL model)

ublic class Singleton{
  public static volatile Singleton INSTANCE;
  // 注意将默认的无参构造方法访问权限符置为private,防止外部调用该构造方法会new出更多对象实例
  private Singleton(){}

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

volatile是一个轻量级的synchronized,它在多处理器开发中保证了共享变量的可见性

利用static机制:

在Java中,类的静态初始化会在类被加载时出发(此过程在JVM内部已加锁,保证线程同步,因此多线程情况下单例不会失效)

ublic class Singleton{
  // 注意将默认的无参构造方法访问权限符置为private,防止外部调用该构造方法会new出更多对象实例
  private Singleton(){}

  public static Singleton getInstance(){
    return SingletonInstanceHolder.INSTANCE;
  }

  public static class SingletonInstanceHolder{
    private static Singleton INSTANCE = new Singleton();
}
}

需要思考一下:单例模式真的能保证只生成一个实例对象吗?
其实要打破实例对象的唯一性,也是有方法来实现的:

  • 使用反射,反射可以无视构造器的私有属性
  • 如果单例类实现了Cloneable接口,还是可以拷贝出许多个实例的
  • Java的Serializable也可以创建出多个实例来的
  • 使用多个类加载器(ClassLoader)来加载单例类,也可以创建出多个实例来的

你可能感兴趣的:(单例模式singleTon的几种常见写法 - Java实现)