1.前言
单例模式可能是设计模式中相对比较简单的而且在工作中应用最频繁的设计模式了,例如系统配置文件的读取工具类要求得保证其实例唯一性。再比如在需要调用计算机底层时,需要一个Java来使用JNI来与其他语言进行交互,此时可能需要保证Java类的实例是唯一的。
那么在编写单例模式时,需要考虑哪些问题呢?

2.简单实现:
常规单例模式实现的原则:
1.实例变量私有化;
2.构造方法私有化;
3.提供静态的基于类的方法放回实例;
遵循这三个原则,可以在最单纯的环境下设计出单例模式。单例模式的最简单实现就是懒汉式和饿汉式,如下:
饿汉式:

public class SingleTon {

  public static SingleTon instance = new SingleTon();
  
  private SingleTon(){}
  
  public static SingleTon getInstance(){
    return instance;
  }
}

特点:线程安全,在类加载初期即完成了对类的实例化;
懒汉式:

public class SingleTon {

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

特点:线程不安全,在首次获取实例时完成对类的实例化;

3.双重加锁:
当然,在进行单例模式的设计时,也需要考虑并发的问题,比如饿汉式的设计,如上简单时,并发情况下就会存在问题,可能会产生多个实例;
双重加锁机制:

public class SingleTon {

  public static SingleTon instance = null;
  
  // .. 内部定义对象锁,当并发条件下,需要竞争syncLock的锁。
  private static final Object syncLock = new Object();
  
  private SingleTon(){}
  
  public static SingleTon getInstance(){
    if(null == instance){
    	// .. 竞争syncLock锁的线程才可以执行代码块内容,其他线程等待
      synchronized (syncLock) {
        if (null == instance) {
        	instance = new SingleTon();
        }
      }
     }
    return instance;
  }

特点:可以防止在多线程环境由于并发导致的多个实例的问题;

4.enum枚举实现单例:
当然即使使用了以上何种方式,在反射和字节码技术面前,还是会毫无抵抗之力,依然可以轻松的生产出多个实例。在JDK1.5中引入了enum枚举类型,依靠枚举类型亦可以实现单利模式,而且可以解决并发和发射层面导致的多个实例的问题。
enum单例实现:

public enum SingleTon {
  insatnce;
  
  private SingleTon(){}
}

特点:基于enum实现的单例模式,完全可以防止反射的多实例化。

**总结:**无论何种单例模式的实现,目的都是一样的,在运行环境内产生唯一的实例。但是具体采用哪种单例模式的实现,需要根据场景具体而定。
本人强烈推荐enum实现单例模式,因为enum防止了各种层面对于类的实例化。当然,如果确定运行环境是单线程,那么完全可以使用最简单的饿汉式或者懒汉式实现,因场景而定。