单列模式在生活中的应用
“Ensure a class has only one instance, and provide a global point of access to it ”
单列模式相信大家都很熟悉,一个类只能创建一个实列。这样做的原因是避免内存浪费,还有某些场景下保持数据一致性问题。
在操作系统中很多场景都被设计成单列。比如网站的计数器,多线程中的线程池,打印机的后台服务,应用程序中的对话框等等。
在我们平时的开发中,也有很多时候用到了单列模式。比如:J2EE 标准中的 ServletContext
和 ServletContextConfig
、Spring框架应用中的 ApplicationContext
、数据库中的连接池等也都是单例模式。
还有全局的ID生成器也需要使用单列模式。当需要定义大量的静态常量和静态方法(如工具类)的环境,可以采用单例模式(还可以直接声明为static
的方式)。
单列模式结构图:
Singleton类称为单例类,通过使用private的构造函数确保了在一个应用中只产生一个实例,并且是自行实例化的(在Singleton中自己使用new Singleton())。
那么单列模式有什么特点呢?
- 单列模式下,类只有一个实列对象。
- 并且这个单列对象由该类自己创建。
- 单列类对外提供一个访问改单列的全局方法。
单列模式好在哪里
单例模式在内存中只有一个实例,减少了内存开支,特别是一个对象需要频繁地创建、销毁时,而且创建或销毁时性能又无法优化,单例模式的优势就非常明显。
单例模式只生成一个实例,所以减少了系统的性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后用永久驻留内存的方式来解决。
单例模式可以避免对资源的多重占用,例如一个写文件动作,由于只有一个实例存在内存中,避免对同一个资源文件的同时写操作。
单例模式可以在系统设置全局的访问点,优化和共享资源访问,例如可以设计一个单例类,负责所有数据表的映射处理。
关于单例你需要注意的
如果统一类型的对象需要在不同场景中发生变化,设计成单列就会引发数据错误问题;如果实例化的对象长时间闲置,系统会被认为是垃圾而被回收,从而导致对象的丢失;不能使用反射创建单列,这会实例化一个新的对象;如果你使用懒汉式做单列模式,那就要注意安全问题了。
关于Spring中的单例模式
在Spring中,每个Bean默认就是单例的,这样做的优点是Spring容器可以管理这些Bean的生命期,决定什么时候创建出来,什么时候销毁,销毁的时候要如何处理,等等。如果采用非单例模(Prototype类型),则Bean初始化后的管理交由J2EE容器,Spring容器不再跟踪管理Bean的生命周期。
单列模式实现方法
实现方式很多:
“饿汉式【优点:线程安全、逻辑简单 缺点:如果这种写法被大量使用的话,导致内存开销增加】 懒汉式【需要考虑线程安全问题,面试最喜欢问这个实现方式】 内部类【内部类会在调用的时候才加载,并只加载一次。利用这个特性可以实现单列模式,但要防止被反射获取】 本地线程实现【利用
ThreadLocal
线程隔离的特性实现】 Map实现【模仿Spring
的Ioc
容器实现】 枚举实现【《Effective Java》作者力荐,线程安全,不用怕被暴力反射破解】 利用CAS实现【状态机制,比较并交换】 ”
具体实现代码可以看看我的这篇文章:
“