设计模式千千万,总是单例最常见。

单例模式的定义

保障一个类仅有一个实例,并提供一个拜访它的全局拜访点。

六种单例的创立形式

1.饿汉式

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

长处:
基于类的加载机制,防止了多线程同步问题,加载速度快。

毛病:
在类加载的时候就实现初始化,没有懒加载,如果没有应用这个实例,会造成内存节约。

2.懒汉式-线程不平安版

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

长处:
第一次调用是才初始化对象,避免浪费资源

毛病:
加载速度慢,线程不平安

3.懒汉式-线程平安版(synchronized加锁)

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

长处:
多线程中保障线程平安
毛病:
每次获取对象实例,都须要进行同步,造成不必要的同步开销。

4.双重校验锁

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;  }}

长处:
线程平安,懒加载,缩小同步开销

毛病:
第一个获取对象速度稍慢,但其在某些状况下也会呈现生效的状况,并不是完满的形式。

这外面应用了两次判空:第一次为了不必要的加锁同步,第二次是确保在instance为null的状况下才创立实例,防止屡次创立。

办法中还是用了关键字volatile对变量进行润饰,有如下几个作用:

1.在Java内存模型中volatile能够保障可见性,及避免程序指令重排序。

2.对象的创立分为如下几个步骤:

instance = new Singleton();
  • 1.为instance分配内存空间
  • 2.初始化instance
  • 3.将instance指向内存地址

如果不加volatile的话,程序的执行程序就可能变成1->3->2,多线程中就会导致线程获取一个没有初始化的实例。例如线程a 执行了1,3, 此时线程b调用getInstance()发现instance不为空,返回instance,但此时instance还未初始化。

5.动态外部类

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

第一次加载类的时候不会初始化instance,只有第一次调用getInstance()的时候才会进行加载SingleHolder并初始化instance,保障线程平安,也能保障实例惟一,举荐应用这种形式。

6.枚举

public enum Singleton {INSTANCE;public void doSomeThing(){}}

默认枚举单例的创立是线程平安的,并且任何状况下都是单例。

以上就是6中常见的单例创立模式,按需应用吧。

单例的应用场景

  • 整个我的项目须要一个共享拜访点或者数据
  • 创立一个对象须要消耗的资源太多,比方拜访数据库资源等
  • 工具类对象