天天看点

一文看懂Java Singleton单例模式

定义: 在整个运行过程中,一个类只有一个实例对象

为什么要用?

有些对象创建消耗资源,如果频繁创建和销毁那将会造成性能浪费,所以我们要用单例模式。

常用的一种方法

public class Singleton {
  private volatile static Singleton singleton;
  private Singleton () {

  }
  public static  Singleton getSingleton() {
    if (null  == singleton) {
      synchronized (Singleton.class) {
        if (null == singleton) {
          singleton = new Singleton();
        }
      }
    }
    return singleton;
  }
}
class main {
  public static void main(String[] args) {
    System.out.println(Singleton.getSingleton());

  }
}      

主要从1、是否线程安全 2 是否懒加载 3 能否反射破坏(人为)

===========================

下面是其他各类方法

一:只适用单线程环境(不推荐)

/**
 * @author kegekeqi
 * @version 1.0
 * @date 2021-12-7 7:50
 */
public class Javasingleton {
  private Javasingleton() {

  }
  private static Javasingleton instance = null;
  public static Javasingleton getInstance() {
    if (null == instance) {
      instance = new Javasingleton();
    }
    return instance;
  }
}      

二、加同步锁前后两次判断实例是否存在,也称为双重检测锁

好处:只有当instance为null时,需要获取同步锁,创建一次实例。当实例被创建,则无需试图加锁。

缺点:用双重if判断,复杂,容易出错。

/**
 * @author kegekeqi
 * @version 1.0
 * @date 2021-12-7 7:50
 */
public class Javasingleton {
  private Javasingleton() {

  }
  private static Javasingleton instance = null;
  public static Javasingleton getInstance() {
    if (null == instance) {
      synchronized (Javasingleton.class) {
        if (null == instance) {
          instance = new Javasingleton();
        }
      }
    }
    return instance;
  }
}      

可能到这里了,大家会提起经常说到的懒汉式、饿汉式和枚举,不要急一一列举,哪种最好用,好好思考一下。

三、饿汉模式

public class HungryManMode {
    private static HungryManMode hungryManMode = new HungryManMode();
    private HungryManMode(){};
    public static HungryManMode getHungryManMode(){
        return hungryManMode;
    }
}      

饿汉模式在类加载的时候就对实例进行创建,避免了多线程重复创建实例的问题,但是类加载就创建一定程度造成了内存的浪费。

四、懒汉模式

public class LazyManMode {
    private static LazyManMode lazyManMode = null;
    private LazyManMode(){};
    public static synchronized LazyManMode getLazyManMode(){
        if(lazyManMode == null){
            lazyManMode = new LazyManMode();
        }
        return lazyManMode;
    }
}      

懒汉模式中在单例需要的时候才进行创建,为了解决存在的并发问题,使用synchronized关键字 进行约束,也就造成了一定的性能浪费

五、枚举

// Singledto.class
public class Singledto implements Serializable {}

// EnumSingleton.class
public enum EnumSingleton {
    ;
    private Singledto singledto;

    private EnumSingleton(){
        singledto = new Singledto();
    }

    public Singledto getSingledto(){
        return singledto;
    }
}      

枚举中的实例被保证只会被实例化一次,所以需要的实例也会保证实例化一次,枚举强烈推荐

六、静态内部类(建议使用)

按需创建实例

由于私有的属性,他人无法使用SingleHolder,不调用SingletonHolder.getInstance()就不会创建实例。

public class JavaSingleton {
  private JavaSingleton() {

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

除此之外,还有利用C#的静态构造函数,确保只创建一个实例。还有利用私有嵌套类型的特性做到真正需要的时候才会创建实例,提高空间使用效率,减少资源的浪费。

补充:比如懒汉式可以人为用反射去破坏,防止这种事情发生可以用枚举类。