1、饿汉式单例模式
饿汉式单例模式的主要特点是:线程安全,调用效率高,不可延时加载。在类初始化一开始就迫不及待地初始化实例,所以这种创建单例的方式叫做饿汉式单例模式。
(1)类初始化时,是一个天然的线程安全环境,在此时立刻创建对象,是线程安全的。
(2)对象提前创建好,调用效率高。
(3)由于饿汉式单例模式在类初始化时立刻加载,所以不可延时加载。
public class SingleInstance { public static SingleInstance SINGLEINSTANCE = new SingleInstance(); private SingleInstance(){ } public static SingleInstance getInstance(){ return SINGLEINSTANCE; } }
2、懒汉式单例模式
懒汉式单例模式的主要特点是:线程不安全,调用效率低,可延时加载。
在类初始化一开始没有初始化实例,而是慢慢地等到真正要获取实例的时候才去做初始化。所以这种创建单例的方式叫做懒汉式单例模式。
(1)线程不安全。可能多个线程同时创建对象。
(2)节省资源。真正用到的时候才创建实例,避免提前创建但可能没被使用浪费资源。
(3)运行效率低。对象没有提前创建好,且每次都需要判空。
public class SingleInstance { public static SingleInstance SINGLEINSTANCE ; private SingleInstance(){ } public static SingleInstance getInstance(){ if(SINGLEINSTANCE == null){ SINGLEINSTANCE = new SingleInstance(); } return SINGLEINSTANCE; } }
3、双重检测锁单例模式
上面的懒汉式单例模式,我们提到了线程不安全。那么为了解决懒汉式单例模式的线程安全问题,诞生了双重检测锁单例模式,
这其实是一种优化后的双重检测锁,使用volatile解决指令重排问题。跟懒汉式单例模式相比,解决了线程安全问题。但是,代码较为繁琐且运行效率更低,毕竟又加锁又双重检测。因此,不推荐使用该方式。
public class SingleInstance { private SingleInstance(){ } private static class Singleton{ private static final SingleInstance SINGLEINSTANCE = new SingleInstance(); } public static SingleInstance getInstance(){ return Singleton.SINGLEINSTANCE; } }
4、枚举单例模式
以上四种单例模式,其实都存在一个隐藏的问题,那就是反射对单例的破坏。枚举单例模式可以防止反射去创建实例。但实际上可能用的不多。
双重检测锁和懒汉式单例模式我们基本可以考虑不去使用。饿汉式是最简单的,在不考虑可能的资源浪费的情况下,可以去使用。更推荐静态内部类,因为完美解决了所有的问题。当然,如果你对反射有要求,那只能选择枚举了。
public enum SingleInstance { INSTANCE; public SingleInstance getInstance(){ return INSTANCE; } }