单例模式是设计模式中使用最为普遍的模式之一。它是一种对象创建模式,用于产生一个对象的具体实例,确保系统中一个类只产生一个实例。在Java中这样的行为能带来两大好处:
1、对于频繁使用的对象,可以省略new操作花费的时间,这对于那些重量级的对象而言,是非常可观的一笔系统开销;
2、由于new操作的次数减少,因而对系统内存的使用频率也会降低,这将减轻GC压力,缩短GC停顿时间。
之所以写这个,是在面试中被问到了这个单例模式的实现方式有哪几种,相对而言,哪种单例模式最常用,当时真的是一脸懵逼,现在昨天晚上看了博客,写了一下代码实现三种单例模式,并且比较他们的优缺点
一、饿汉式单例模式
1 /** 2 * 饿汉式单例模式(饿汉式是由 the singleton instance is early created at complie time中的early音译过来的)<br> 3 * 优点:没有加锁,执行效率会提高。<br> 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 * 懒汉式单例模式<br> 3 * 优点:第一次调用才初始化,避免内存浪费。 <br> 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()方法中没有锁,这使得在高并发环境下性能优越。<br> 4 * 其次,只有在getInstance()方法被第一次调用时,StaticSingleton的实例才会被创建。因为这种方式巧妙的使用了内部类和类的初始化方式。<br> 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 }