单例模式(Singleton Pattern)
单例模式:确保一个类只有一个实例,并提供一个全局访问点。
为什么需要单例模式?
有一些对象只需要一个,比如:线程池,对话框,注册表的对象,日志对象,打印机、显卡等设备的驱动程序对象。如果这些类有多个实例,会导致许多问题的产生。
1.第一种方式
是否延迟初始化:是
是否多线程安全:否
public class Singleton { private static Singleton instance = null; private SingleObject() {} public static Singleton getInstance() { if(instance == null){ instance = new Singleton(); } return instance; } }
这种方法只适合在单线程环境下。
2.第二种方式:
是否延迟初始化:是
是否多线程安全:是
public class Singleton { private static Singleton instance; private Singleton() {} public static synchronized Singleton getInstance() { if(instance == null){ instance = new Singleton(); } return instance; } }
这种方法采用synchronized关键字,迫使每个线程进入getInstance()方法之前,要等别的线程离开该方法,也就是不会有两个线程同时进入该方法。
缺点是:同步会降低性能,而且只有第一次执行此方法时,才很真正需要同步,一旦单例类被实例化后,之后每次调用,都不需要同步了。
3.第三种方式:
是否延迟初始化:否
是否多线程安全:是
public class Singleton { private static Singleton instance = new Singleton(); private Singleton() {} public static Singleton getInstance(){ return instance; } }
当类被加载时,马上实例化Singleton对象。
缺点是,如果程序整个运行过程没有使用过Singleton对象,会导致浪费资源,因为该对象一直占用内存。
第四种方式:
是否延迟初始化:是
是否多线程安全:是
public class Singleton { private volatile static Singleton instance; private Singleton() {} public static Singleton getInstance() { if(instance == null){ synchronized(Singleton.class) { if(instance == null) { instance = new Singleton(); } } } return instance; } }
这种方法利用双重检查加锁,能减少getInstance()同步,首先检查实例是否已经创建,如果未创建,进行同步,否则直接返回已经存在的实例。
第五种方式:
是否延迟初始化:是
是否多线程安全:是
public class Singleton { private static class SingletonInner { private static Singleton instance = new Singleton(); } private Singleton() {} public static Singleton getInstance() { return SingletonInner.instance; } }
这种方式在Singleton类里面写了个内部类,实现当Singleton类被加载时,不会实例化Singleton对象,而是调用了Singleton.getInstance()时,将SingletonInner类加载时,Singleton才会实例化。相比第三种方法更加合理。
第六种方法:
是否延迟初始化:否
是否多线程安全:是
public enum Singleton { INSTANCE; private Singleton() { } }
自JDK1.5起才能使用,更加简洁,自动支持序列化机制,绝对防止多次实例化,不能通过reflection attack来调用私有构造方法。