单例模式是设计模式中使用最为普遍的模式之一。它是一种对象创建模式,用于产生一个对象的具体实例,确保系统中一个类只产生一个实例。在Java中这样的行为能带来两大好处:
1、对于频繁使用的对象,可以省略new操作花费的时间,这对于那些重量级的对象而言,是非常可观的一笔系统开销;
2、由于new操作的次数减少,因而对系统内存的使用频率也会降低,这将减轻GC压力,缩短GC停顿时间。之所以写这个,是在面试中被问到了这个单例模式的实现方式有哪几种,相对而言,哪种单例模式最常用,当时真的是一脸懵逼,现在昨天晚上看了博客,写了一下代码实现三种单例模式,并且比较他们的优缺点
一、饿汉式单例模式1 /** 2 * 饿汉式单例模式(饿汉式是由 the singleton instance is early created at complie time中的early音译过来的) 3 * 优点:没有加锁,执行效率会提高。 4 * 缺点:类加载时就初始化,浪费内存。 5 * 6 * @author ssc 7 * @Date 2019.03.25 8 */ 9 public class EarlySingleton {10 11 private static EarlySingleton instance = new EarlySingleton();12 13 private EarlySingleton(){14 15 }16 17 public static EarlySingleton getInstance(){18 return instance;19 }20 21 }
二、懒汉式单例模式
1 /** 2 * 懒汉式单例模式 3 * 优点:第一次调用才初始化,避免内存浪费。 4 * 缺点:必须加锁synchronized 才能保证单例,(如果两个线程同时调用getInstance方法,会出错)但加锁会影响效率。 5 * 6 * @author ssc 7 * @Date 2019.03.25 8 * 9 */10 public class LazySingleton {11 12 private static LazySingleton instance = null;13 14 private LazySingleton(){15 16 }17 18 public static synchronized LazySingleton getInstance(){19 if(instance == null){20 instance = new LazySingleton();21 }22 return instance;23 }24 }
三、登记式单例模式
1 /** 2 * 登记式模式(holder) 3 * 这种方式实现的单例同时拥有前两种方式的优点。首先getInstance()方法中没有锁,这使得在高并发环境下性能优越。 4 * 其次,只有在getInstance()方法被第一次调用时,StaticSingleton的实例才会被创建。因为这种方式巧妙的使用了内部类和类的初始化方式。 5 * 内部类SingletonHolder被声明为private,这使得我们不可能在外部访问并初始化它。而我们只可能在getInstance()内部对SingletonHolder类进行初始化,利用虚拟机的类初始化机制创建单例。 6 * 7 * @author ssc 8 * @Date 2019.03.25 9 *10 */11 public class StaticSingleton {12 13 private StaticSingleton(){14 15 }16 17 private static class SingletonHolder {18 private final static StaticSingleton instance = new StaticSingleton();19 }20 21 public static StaticSingleton getInstance(){22 return SingletonHolder.instance;23 }24 25 }