单例模式的几种实现
简单点说,就是一个应用程序中,某个类的实例对象只有一个,你没有办法去new,因为构造器是被private修饰的,一般通过getInstance()的方法来获取它们的实例。getInstance()的返回值是一个对象的引用,并不是一个新的实例,所以不要错误的理解成多个对象。单例模式实现起来也很容易,直接看demo吧
懒汉式写法(线程不安全)
public class Singleton { private static Singleton singleton; private Singleton() { } public static Singleton getInstance() { if (singleton == null) { singleton = new Singleton(); } return singleton; } }
按照我的习惯,我恨不得写满注释,怕你们看不懂,但是这个代码实在太简单了,所以我没写任何注释,如果这几行代码你都看不明白的话,那你可以洗洗睡了,等你睡醒了再来看我的博客说不定能看懂。
上面的是最基本的写法,也叫懒汉写法(线程不安全)下面我再公布几种单例模式的写法:
懒汉式写法(线程安全)
public class Singleton { private static Singleton instance; private Singleton (){} public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
饿汉式写法
线程安全,比较常用,但容易产生垃圾,因为一开始就初始化
public class Singleton { private static Singleton instance = new Singleton(); private Singleton (){} public static Singleton getInstance() { return instance; } }
静态内部类
public class Singleton { private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } private Singleton (){} public static final Singleton getInstance() { return SingletonHolder.INSTANCE; } }
只有第一次调用getInstance方法时,虚拟机才加载 SingletonHolder并初始化INSTANCE,只有一个线程可以获得对象的初始化锁,其他线程无法进行初始化,保证对象的唯一性。目前此方式是所有单例模式中最推荐的模式,但具体还是根据项目选择。
枚举
public enum Singleton { INSTANCE; public void whateverMethod() { } }
这种方式是Effective Java作者Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象,可谓是很坚强的壁垒啊,不过,个人认为由于1.5中才加入enum特性,用这种方式写不免让人感觉生疏。
双重校验锁
public class Singleton { private volatile static Singleton singleton; private Singleton (){} public static Singleton getSingleton() { if (singleton == null) { synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } } return singleton; } }
线程安全,延迟初始化。这种方式采用双锁机制,安全且在多线程情况下能保持高性能
总结:我个人比较喜欢静态内部类写法和饿汉式写法,其实这两种写法能够应付绝大多数情况了。其他写法也可以选择,主要还是看业务需求吧。