java设计模式:单例模式(Singleton Pattern)
单例模式(Singleton Pattern)
单例就是在系统内存中只存在一个对象,用来节约系统资源,减少频繁创建和销毁对象带来的系统开销。
从功能上,单例模式维护系统有且仅有一个实例,并提供全局的访问点,其算是一种职责型模型。
懒汉式单例类,在第一次调用的时候实例化自己,这种单例模式线程不安全,多线程时不能保证类的实例是单例的。代码参如下。
public class Singleton { // 构造器私有化 private Singleton() {} private static Singleton instance = null; public static Singleton getInstance() {//提供全局的访问点 if (instance == null) { instance = new Singleton(); } return instance; } }
该实现方式的优点如下:
★由于实例是在 instance属性方法内部创建的,因此类可以使用附加功能(例如,对子类进行实例化),即使它可能引入不想要的依赖性。
★直到对象要求产生一个实例才执行实例化;这种方法称为“惰性实例化”。惰性实例化避免了在应用程序启动时实例化不必要的实例。
饿汉式单例是指在类初始化时就自行实例化,所以天生线程安全,该实现方式的优点是获取实例不需要每次都进行判断,节约运行时间,代码如下:
//饿汉式单例,在类初始化时已经自行实例化,所以天生线程安全 public class Singleton { private Singleton() { } private static final Singleton singleton = new Singleton(); public static Singleton getInstance() { return singleton; } }
单例在多线程中使用需要考虑线程安全问题,饿汉式单例虽然是线程安全的,但是它在该类加载的时候就会直接实例化一个静态对象出来,当系统中这样的类较多时,会使得启动速度变慢,所以这种方式适合在小系统中。
当系统中这样的类比较多时,可以采用同步方法来处理进行延迟加载,代码如下:
public class Singleton { private Singleton() { } private static Singleton single = null; // 静态工厂方法,加同步保证线程安全 public static synchronized Singleton getInstance() { if (single == null) { single = new Singleton(); } return single; } }
这种方式虽然线程安全,但是同步方法会带来性能问题。解决这个问题可以参考后续几种方式。
代码如下:
public class Singleton { private static Singleton instance; private Singleton() { } public static Singleton getInstance() { //先判断一次引用,所有引用不为null的情况都不用进入同步方法了 if (instance == null) { //对获取实例的方法进行同步,此时引用为null多个请求每次只有一个可以进入同步方法, synchronized (Singleton.class) { //只要第一次实例化后,后续引用都不为null,此时再判断一次引用的情况,就可以保证只实例化一次 if (instance == null) instance = new Singleton(); } } return instance; } }
代码如下:
//静态内部类实现方式(既线程安全,又避免同步带来的性能影响) public class Singleton { private static class LazyHolder{ private static final Singleton INSTANCE = new Singleton(); } private Singleton() {} // 静态工厂方法,加同步保证线程安全 public static final Singleton getInstance() { return LazyHolder.INSTANCE; } }
代码如下:
//创建枚举默认就是线程安全的,无需double checked locking。 public enum SingletonEnum { INSTANCE { public void singleMethod() { //some code write here } }; protected abstract void singleMethod(); }
单例模式根据单例产生的时机可分为懒汉模式和饿汉模式,其中懒汉模式会延迟加载这样可以避免不必要的单例实例化,节省空间;而饿汉模式在类装载的时候就实例化对象,在获取实例的时可以直接获取,节省时间。
从线程安全方面考虑,饿汉式单例天生线程安全,而懒汉式需要一些处理才行。其中同步方法因为使用同步关键字从而使线程安全,但是会影响性能;双重锁定将实例类作为监视器,并通过两次判断从而保证线程安全,
并且有较好的运行性能。另外枚举方式实现单例代码简单,而且有序列话和线程安全的保证,是比较好的单例实现方式,所以小伙伴们快快get起来吧!