概述
单例模式(Singleton Pattern),创建对象模式之一,单例模式确保一个类只能创建一个实例。单例模式适用于一个系统要求一个类只有一个实例时,比如Swing窗体,只需要一个实例。如果一个类可以同时存在多个实例,那就不需要使用单例模式。单例模式很容易被滥用。下面看一下代理模式的几种实现方式。
实现
实现单例模式要两点,一是不能让外界创建对象,所以需要构造器私有化;二是需要提供得到单例对象的方法。
饿汉模式
/** * 单例之饿汉模式 */ public class Singleton { private static Singleton instance =new Singleton(); private Singleton() {} public static Singleton getInstance() { return instance; } } |
该模式是类加载的的时候创建好一个静态对象,不管使用不使用,对象已经创建好了,并且是线程安全的。
懒汉模式
/** * 单例之懒汉 */ public class Singleton { private static Singleton instance; private Singleton() {} public static synchronized Singleton getInstance() { if(instance ==null) { instance = new Singleton(); } return instance; } } |
该模式很懒,不用的时候不会创建对象,只有用的时候才会创建,但在多线程的情况下,需要让方法互斥,才能保证只会创建一个实例,如果不加synchronized,当多个线程同时获取实例时,就有可能创建多个实例。(可以测试一下)
双重锁定
/** * 双重锁定 */ public class Singleton { private static Singleton instance; private Singleton() {} public static Singleton getInstance() { if(instance ==null) { synchronized (Singleton.class) { if (instance ==null) { instance =new Singleton(); } } } return instance; } } |
第一个instance == null是判断当前是否为空,如果为空才对创建实例的代码块上互斥锁,第二个instance == null是两个线程互斥了,第一个线程创建完对象,第二个线程直接返回。这种方式是在懒汉模式上的一个进化,避免了无用的互斥开销。这个是在《大话设计模式》上看到的,大话是用的C#,百度一下,这种方式不适用于java,基于java内存模型有时会失效,我没想明白什么时候会失效,明天再研究下。
总结
单例模式由于构造器是私有化的,所以单例的类不能被继承。优缺点分析,饿汉模式,类加载的时候就会创建单例对象,保证了多线程情况下的单例,同时有可能这个单例对象永远也不会被用到;懒汉模式,只有用到单例的时候才会创建对象,不用就不会创建,多线程情况下互斥开销较大。使用哪种情况全屏自己爱好,企业级应用应该不会在这点内存上耗费时间。