设计模式之单例模式
定义:单例模式主要作用是保证在Java应用程序中,一个类Class只有一个实例存在
单例模式为我们提供了这样的实现。使用单例的好处还在于可以节省内存,因为它限制了实例的个数,有利于Java的垃圾回收(garbage collection)。
我们常常看到工厂模式中类加载器(class loader)中也是用单例模式来实现,因为被装入的来实际也属于资源。
使用:一般单例模式通常有两种形式 -- 懒汉式和饿汉式
懒汉式:第一次调用时初始化,避免内存浪费,使用双重检查可以保证在多线程情况的线程安全
1 public class Singleton { 2 private static Singleton instance = null; 3 /** 4 * 让构造函数私有化,这样该类就不会在类外被实例化 5 */ 6 private Singleton() { 7 } 8 public static Singleton getInstance() { 9 // 第一次使用时生成对象 10 if (instance == null) { 11 synchronized (Singleton.class) { 12 if (instance == null) { 13 instance = new Singleton(); 14 } 15 } 16 } 17 return instance; 18 } 19 }
饿汉式:类加载时初始化,线程安全,执行效率高,但是容易产生垃圾对象
1 public class Singleton { 2 // 在类装载时就实例化Singleton的一个对象 3 private static Singleton instance = new Singleton(); 4 5 /** 6 * 让构造函数私有化,这样该类就不会在类外被实例化 7 */ 8 private Singleton(){} 9 10 /** 11 * 提供一个供外部访问的方法获取唯一可用的对象 12 * @return 返回唯一可用的对象 13 */ 14 public static Singleton getInstance(){ 15 return instance; 16 } 17 18 // 类中其他方法尽量被public修饰,方便被外界直接调用 19 }
使用场景:要求一个类有且仅有一个对象,就可以采用单例模式。
最佳实践:在spring中,每个bean默认使用的就是单例,这样做的优点是Spring容器可以管理这些bean的生命周期。如果采用非单例模式,则bean初始化话后的管理交给J2EE容器,Spring不再管理。
注意事项:使用单例模式需要注意的一点时JVM的垃圾回收机制。当一个单例对象在内存中长久不使用,在CPU空闲的时候该对象会被清理掉,下次再调用的时候再重新创建一个对象,这样如果我们在应用中使用该单例类作为类似计数器等管理,就会出现恢复原状的故障。如果确定使用单例模式来作为类似计数器等作用,可以使用下面的方法来解决此问题
- 由容器管理单例的生命周期:JavaEE容器或者框架的容器(如Spring)可以让对象长久贮存。
- 状态随时记录:使用异步的方式,记录状态的变化,写入数据库,确保单例对象在重新初始化的时候也可以从保存的资源中获得销毁前的数据,避免数据丢失。
单例模式还有多种设计方式,这里不再一一赘述,大家有想法可以留言一起交流。