单利模式的优缺点和使用场景
首先介绍一下单例模式:
单例模式(Singleton),也叫单子模式,是一种常用的软件设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息。这种方式简化了在复杂环境下的配置管理。
实现单例模式的思路是:
一个类能返回对象一个引用(永远是同一个)和一个获得该实例的方法(必须是静态方法,通常使用getInstance这个名 称);当我们调用这个方法时,如果类持有的引用不为空就返回这个引用,如果类保持的引用为空就创建该类的实例并将实例的引用赋予该类保持的引用;同时我们 还将该类的构造函数定义为私有方法,这样其他处的代码就无法通过调用该类的构造函数来实例化该类的对象,只有通过该类提供的静态方法来得到该类的唯一实例。
需要注意的地方:
单例模式在多线程的 应用场合下必须小心使用。如果当唯一实例尚未创建时,有两个线程同时调用创建方法,那么它们同时没有检测到唯一实例的存在,从而同时各自创建了一个实例, 这样就有两个实例被构造出来,从而违反了单例模式中实例唯一的原则。 解决这个问题的办法是为指示类是否已经实例化的变量提供一个互斥锁(虽然这样会降低效率)。
优点:
1.在单例模式中,活动的单例只有一个实例,对单例类的所有实例化得到的都是相同的一个实例。这样就
防止其它对象对自己的实例化,确保所有的对象都访问一个实例
2.单例模式具有一定的伸缩性,类自己来控制实例化进程,类就在改变实例化进程上有相应的伸缩性。
3.提供了对唯一实例的受控访问。
4.由于在系统内存中只存在一个对象,因此可以
节约系统资源,当
需要频繁创建和销毁的对象时单例模式无疑可以提高系统的性能。
5.允许可变数目的实例。
6.避免对共享资源的多重占用。
缺点:
1.不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。
2.由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。
3.单例类的职责过重,在一定程度上违背了“单一职责原则”。
4.滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。
使用注意事项:
1.使用时不能用反射模式创建单例,否则会实例化一个新的对象
2.使用懒单例模式时注意线程安全问题
3.饿单例模式和懒单例模式构造方法都是私有的,因而是不能被继承的,有些单例模式可以被继承(如登记式模式)
适用场景:
单例模式只允许创建一个对象,因此节省内存,加快对象访问速度,因此对象需要被公用的场合适合使用,如多个模块使用同一个数据源连接对象等等。如:
1.需要频繁实例化然后销毁的对象。
2.创建对象时耗时过多或者耗资源过多,但又经常用到的对象。
3.有状态的工具类对象。
4.频繁访问数据库或文件的对象。
以下都是单例模式的经典使用场景:
1.资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如上述中的日志文件,应用配置。
2.控制资源的情况下,方便资源之间的互相通信。如线程池等。
应用场景举例:
1.外部资源:每台计算机有若干个打印机,但只能有一个PrinterSpooler,以避免两个打印作业同时输出到打印机。内部资源:大多数软件都有一个(或多个)属性文件存放系统配置,这样的系统应该有一个对象管理这些属性文件
2. Windows的Task Manager(任务管理器)就是很典型的单例模式(这个很熟悉吧),想想看,是不是呢,你能打开两个windows task manager吗? 不信你自己试试看哦~
3. windows的Recycle Bin(回收站)也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。
4. 网站的计数器,一般也是采用单例模式实现,否则难以同步。
5. 应用程序的日志应用,一般都何用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。
6. Web应用的配置对象的读取,一般也应用单例模式,这个是由于配置文件是共享的资源。
7. 数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。数据库软件系统中使用数据库连接池,主要是节省打开或者关闭数据库连接所引起的效率损耗,这种效率上的损耗还是非常昂贵的,因为何用单例模式来维护,就可以大大降低这种损耗。
8. 多线程的线程池的设计一般也是采用单例模式,这是由于线程池要方便对池中的线程进行控制。
9. 操作系统的文件系统,也是大的单例模式实现的具体例子,一个操作系统只能有一个文件系统。
10. HttpApplication 也是单位例的典型应用。熟悉ASP.Net(IIS)的整个请求生命周期的人应该知道HttpApplication也是单例模式,所有的HttpModule都共享一个HttpApplication实例.
实现单利模式的原则和过程:
1.单例模式:确保一个类只有一个实例,自行实例化并向系统提供这个实例
2.单例模式分类:饿单例模式(类加载时实例化一个对象给自己的引用),懒单例模式(调用取得实例的方法如getInstance时才会实例化对象)(java中饿单例模式性能优于懒单例模式,c++中一般使用懒单例模式)
3.单例模式要素:
a.私有构造方法
b.私有静态引用指向自己实例
c.以自己实例为返回值的公有静态方法
1.饿汉式:单例实例在类装载时就构建,急切初始化。(预先加载法)
/**
* 饿汉式(推荐)
*
*/
public class Test {
private Test() {
}
public static Test instance = new Test();
public Test getInstance() {
return instance;
}
}
优点
1.线程安全
2.在类加载的同时已经创建好一个静态对象,调用时反应速度快
缺点
资源效率不高,可能getInstance()永远不会执行到,但执行该类的其他静态方法或者加载了该类(class.forName),那么这个实例仍然初始化
2.懒汉式:单例实例在第一次被使用时构建,延迟初始化。
class Test {
private Test() {
}
public static Test instance = null;
public static Test getInstance() {
if (instance == null) {
//多个线程判断instance都为null时,在执行new操作时多线程会出现重复情况
instance = new Singleton2();
}
return instance;
}
}
优点:
避免了饿汉式的那种在没有用到的情况下创建事例,资源利用率高,不执行getInstance()就不会被实例,可以执行该类的其他静态方法。
缺点:
懒汉式在单个线程中没有问题,但多个线程同事访问的时候就可能同事创建多个实例,而且这多个实例不是同一个对象,虽然后面创建的实例会覆盖先创建的实例,但是还是会存在拿到不同对象的情况。解决这个问题的办法就是加锁synchonized,第一次加载时不够快,多线程使用不必要的同步开销大。
3.双重检测
class Test {
private Test() {
}
public static Test instance = null;
public static Test getInstance() {
if (instance == null) {
synchronized (Test.class) {
if (instance == null) {
instance = new Test();
}
}
}
return instance;
}
}
优点
资源利用率高,不执行getInstance()就不被实例,可以执行该类其他静态方法
缺点
第一次加载时反应不快,由于java内存模型一些原因偶尔失败
4.静态内部类
class Test {
private Test() {
}
private static class SingletonHelp {
static Test instance = new Test();
}
public static Test getInstance() {
return SingletonHelp.instance;
}
}
优点
资源利用率高,不执行getInstance()不被实例,可以执行该类其他静态方法
缺点
第一次加载时反应不够快
总结:
一般采用饿汉式,若对资源十分在意可以采用静态内部类,不建议采用懒汉式及双重检测
转载请注明出处:
http://renyuan-1991.iteye.com/blogs/2246557
希望爱好编程的小伙伴能加这个群,互相帮助,共同学习。群号: 141877583
分享到:
相关推荐
这种模式在很多场景下非常有用,比如数据库连接池、日志处理、线程池等,在这些场景中通常希望在整个系统中只存在一个实例来共享资源或控制行为。 #### 二、单例设计模式的重要性 在多线程环境下,如果多个线程...
单例模式的优缺点: - 优点:节省系统资源,对全局唯一的系统服务提供方便快捷的访问入口,如数据库连接池、缓存管理等。 - 缺点:违反了“单一职责原则”,单例类往往承担了过多职责;不易于进行单元测试;如果单例...
这个例子中的“单利模式”可能指的是在C++环境中实现的单例模式,而“不是double click”可能是在说明这不是通过双击或者某种特定的用户交互来创建实例,而是通过编程逻辑来确保单例的存在。 首先,我们来看一下`...
总结起来,Java中的单例模式有多种实现,每种都有其优缺点。开发者应根据项目需求选择适合的实现方式,比如对性能要求较高的场景可以选择静态内部类或枚举,而对内存占用敏感的场景则可能更适合饿汉式。通过学习和...
我们还讨论了单例设计模式的优点和缺点,以及在 Java 中的应用场景。 单例设计模式是一种非常重要的设计模式,在 Java 中的应用非常广泛。通过私有化构造方法和控制对象的实例化,可以避免对象的滥用和提高程序的...
下面将详细介绍单例模式的实现方式以及其优缺点。 ### 单例模式的实现方式: 1. **饿汉式(静态常量)**: 在类加载时就完成了初始化,所以没有安全问题。但这种方式会浪费内存,因为不管是否使用,类装载后实例...
- **懒汉式**:线程不安全,通常需要加锁保证单例的唯一性。 - **双重检查锁定**:在懒汉式的基础上改进,保证线程安全的同时提高效率。 - **应用场景**:数据库连接池、线程池等资源控制场合。 **4. 建造者模式...
四、状态模式的优缺点 优点: 1. 封装了转换规则,状态模式把改变对象状态的逻辑转移到具体的上下文类或状态类中,使代码更加清晰。 2. 结构清晰,状态模式将与状态相关的行为集中在一个类中,使得代码易于理解和...
在“访问者模式”的例子中,我们将深入理解其核心概念和应用场景。 访问者模式的核心组件包括: 1. **元素(Element)接口/抽象类**:这是对象结构中的基本组成单元,定义了一个接受访问者的接口。 2. **具体元素...
单例模式是设计模式中的一种,其主要目的是确保一个类...5. 如何在保证单例模式的同时,增加可配置性或者实现不同实例的切换? 理解并熟练掌握单例模式的实现方式和应用场景,对于编写高效、可维护的代码至关重要。
1. **双重检查锁定(Double-checked locking)**:这是一种常用的解决线程安全问题的方法,可以在不牺牲性能的情况下保证单例模式的线程安全。 2. **使用`@synchronized`关键字**:在获取实例的方法中使用 `@...
4. **枚举单例**:利用枚举的特性来保证单例的线程安全和实例唯一性。但是枚举方式不支持延迟初始化。代码如下: ```csharp public enum Singleton { Instance } public sealed class SingletonInstance { ...
Java 单例模式是一种设计...每种方式都有其优缺点,开发者需要根据实际需求和性能考虑选择合适的实现。同时,需要注意的是,过度使用单例可能导致系统设计过于紧密耦合,不利于测试和扩展,因此在设计时需谨慎考虑。
每种方式都有其优缺点,适用场景也不同。 1. **懒汉式**:延迟初始化,只有在第一次调用getInstance()方法时才创建实例。但是这种方式存在线程安全问题,如果多个线程同时调用getInstance(),可能会创建多个实例。...
每个模式都有其特定的使用场景和优缺点。在实际开发中,开发者应当根据项目的具体需求和场景,选择合适的设计模式来解决问题。设计模式不仅是一组实现的代码,更是解决问题的思想和方法。通过学习设计模式,开发者...
每种实现方式都有其优缺点,选择哪种方式取决于具体的应用场景。例如,如果对性能要求较高,可以考虑DCL或静态内部类;如果代码简洁性更重要,枚举方式可能是最佳选择。在实际应用中,应根据项目需求来决定采用哪种...
每个模式都有其特定的应用场景和优缺点,理解并灵活运用这些模式能够提高代码的可读性、可维护性和复用性。 例如,建造者模式将复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示;装饰器模式允许...
值得注意的是,从MongoDB 4.0.1版本开始,官方不再支持主从模式,推荐使用副本集(Replica Sets)代替,因为副本集提供了自动故障转移和更高级的复制功能。在升级到4.0版本之后,必须采用副本集来构建高可用性的...
### ShardingSphere实战场景及与Atlas和Mycat对比 #### 一、ShardingSphere简介与实战场景 **ShardingSphere** 是一个分布式数据库中间件项目,由阿里巴巴开源,后来被捐赠给了 Apache 基金会。它主要解决的是...