设计模式之单例模式 (设计模式基础知识)

本文目录导航:

设计模式之单例模式

单例设计模式理解起来非常简单。

一个类只允许创建一个对象(或者实例),那这个类就是一个单例类,这种设计模式就叫单例模式。

设计模式之单例模式 (设计模式基础知识)

下面的示例中如果每个类都创建一个 Logger 实例,就可能造成日志内容被覆盖的情况。

如果有些数据在系统中只应保存一份,那就比较适合设计为单例类。

比如,配置信息类,全局 ID 生成器等。

要实现一个单例,我们要考虑以下几点:

懒汉式相对于饿汉式的优势是「支持延迟加载」 。

但缺点也很明显,因为使用了 synchronized 关键字导致这个方法的「并发度很低」 。

如果这个单例类偶尔会被用到,那这种实现方式还可以接受。

但是,如果频繁地用到,就会导致性能瓶颈,这种实现方式就不可取了。

这是一种既支持延迟加载、又支持高并发的单例实现方式。

在 java1.5 以下 instance = new Singleton(); 有指令重排问题,需要给 instance 成员变量加上 volatile 关键字,java1.5 之后不会再这个问题。

这种方式利用了 Java 的静态内部类,有点类似饿汉式,但又能做到了延迟加载。

当外部类 Singleton 被加载的时候,并不会创建 SingletonHolder 实例对象。

只有当调用 getInstance() 方法时,SingletonHolder 才会被加载,这个时候才会创建 instance。

insance 的唯一性、创建过程的线程安全性,都由 JVM 来保证。

所以,这种实现方法既保证了线程安全,又能做到延迟加载。

这是一种最简单的实现方式,基于枚举类型的单例实现。

这种实现方式是通过 Java 枚举类型本身的特性,保证了实例创建的线程安全性和实例的唯一性。

上面的单例类对象是进程唯一的,一个进程只能有一个单例对象。那如何实现一个线程唯一的单例呢?

假设 IdGenerator 是一个线程唯一的单例类。

在线程 A 内,我们可以创建一个单例对象 a。

因为线程内唯一,在线程 A 内就不能再创建新的 IdGenerator 对象了,而线程间可以不唯一,所以,在另外一个线程 B 内,我们还可以重新创建一个新的单例对象 b。

我们通过一个 ConcurrentHashMap 来存储对象,其中 key 是线程 ID,value 是对象。

这样我们就可以做到,不同的线程对应不同的对象,同一个线程只能对应一个对象。

实际上,Java 语言本身提供了 ThreadLocal 工具类,可以更加轻松地实现线程唯一单例。

单例模式介绍和使用场景及Spring单例模式的使用

1.什么是单例模式

单例模式(SingletonPattern)是Java中最简单的设计模式之一。

这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。

这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

2.单例模式的优点/缺点和使用场景2.1单例模式的优点

提供了对唯一实例的受控访问

由于系统中内存只存在一个对象,因此可以节约系统的的资源,对于一些频繁的创建和销毁的对象单例模式无意可以提供系统的性能

单例模式可以允许可变的数目的实例,使用单利模式进行扩展,使用控制单利对象相似的方法获取指定个数的实例,及解决了单利对象,共享过多,而有损性能的问题

2.2单例模式的缺点

由于单例模式,不是抽象的所以可扩展性比较差

职责过重,在一定程度上违背了单一职责

滥用单例将带来一些负面的问题,如为了节省资源将数据库连接池对象设计为单例模式,可能会导致共享连接池对象的程序过多未出而出现的连接池溢出,如果实例化对象长时间不用系统就会被认为垃圾对象被回收,这将导致对象状态丢失

2.3单例模式的使用场景

开发工具类库中的很多工具类都应用了单例模式,比例线程池、缓存、日志对象等,它们都只需要创建一个对象。

3.单例模式的12种写法3.1饿汉式(静态变量)publicclassSingleton{privatestaticSingletoninstance=newSingletion();privateSingletion(){}publicstaticSingletongetInstance(){returninstance;}}3.2饿汉式(静态常量)publicclassSingleton{privatefinalstaticSingletonINSTANCE=newSingleton();privateSingleton(){}publicstaticSingletongetInstance(){returnINSTANCE;}}3.3饿汉式(静态代码块)publicclassSingleton{privatestaticSingletoninstance;static{instance=newSingleton();}privateSingleton(){}publicstaticSingletongetInstance(){returninstance;}}

上面三种写法本质上其实是一样的,也是各类文章在介绍饿汉式时常用的方式。

但使用静态final的实例对象或者使用静态代码块依旧不能解决在反序列化、反射、克隆时重新生成实例对象的问题。

序列化:一是可以将一个单例的实例对象写到磁盘,实现数据的持久化;二是实现对象数据的远程传输。

当单例对象有必要实现Serializable接口时,即使将其构造函数设为私有,在它反序列化时依然会通过特殊的途径再创建类的一个新的实例,相当于调用了该类的构造函数有效地获得了一个新实例!

3.4懒汉式(线程不安全)publicclassSingleton{privatestaticSingletoninstance;privateSingleton(){}publicstaticSingletongetInstance(){if(instance==null){instance=newSingleton();}returninstance;}}3.5懒汉式(线程安全,存在同步开销)classSingleton{privatestaticSingletonintance=null;privateSingleton(){//私有构造函数}publicstaticsynchronizedSingletongetInstance(){if(intance==null){intance=newSingleton();}returnintance;}}3.6懒汉式(线程假装安全,同步代码块)classSingleton{privatestaticSingletonsingleton;privateSingleton(){}publicstaticSingletongetInstance(){if(singleton==null){//4.加入同步代码块synchronized(){singleton=newSingleton();}}returnsingleton;}}3.7DCL「双重检测锁:DoubleCheckedLock」(假)publicclassSingleton{privatestaticSingletoninstance;privateSingleton(){}publicstaticSingletongetInstance(){if(instance==null){synchronized(){if(instance==null){instance=newSingleton();}}}returninstance;}}3.8DCL「双重检测锁:DoubleCheckedLock」单例(真)publicclassSingleton{privatestaticvolatileSingletoninstance;privateSingleton(){}publicstaticSingletongetInstance(){if(instance==null){synchronized(){instance=newSingleton();}}returninstance;}}3.9静态内部类(推荐使用)publicclassSingleton{privateSingleton(){}privatestaticclassSingletonInstance(){privatestaticfinalSingletonINSTANCE=newSingleton();}publicstaticSingletongetInstance(){;}}3.10枚举类单例模式publicenumSingleton{INSTANCE;privateResourceinstance;Singleton(){instance=newResource();}publicResourcegetInstance(){returninstance;}publicstaticclassResource{privateResource(){}}}3.11登记式单例--使用Map容器来管理单例模式publicclassSingleton{privatefinalstaticSingletonINSTANCE=newSingleton();privateSingleton(){}publicstaticSingletongetInstance(){returnINSTANCE;}}03.12内部枚举类publicclassSingleton{privatefinalstaticSingletonINSTANCE=newSingleton();privateSingleton(){}publicstaticSingletongetInstance(){returnINSTANCE;}}依赖注入对单例的使用

在AbstractBeanFactory中

publicclassSingleton{privatefinalstaticSingletonINSTANCE=newSingleton();privateSingleton(){}publicstaticSingletongetInstance(){returnINSTANCE;}}24.1doGetBean中getSingletonpublicclassSingleton{privatefinalstaticSingletonINSTANCE=newSingleton();privateSingleton(){}publicstaticSingletongetInstance(){returnINSTANCE;}}34.2getSingleton的实现

返回在给定名称下注册的(原始)单例对象,检查已经实例化的单例并允许提前对当前创建的单例的引用(解析循环引用)。

publicclassSingleton{privatefinalstaticSingletonINSTANCE=newSingleton();privateSingleton(){}publicstaticSingletongetInstance(){returnINSTANCE;}}4

作者:ZhangSan_Plus

什么是Java单例模式啊?

单例模式确保一个类只有一个实例,并向整个系统提供这个实例。

其特点包括:一个类只能有一个实例,自己创建这个实例,并在整个系统中提供这个实例。

例如,在对象图中,有一个“单例对象”,而“客户甲”、“客户乙”和“客户丙”是单例对象的三个客户对象。

所有客户对象共享同一个单例对象。

单例对象持有对自己实例的引用。

Singleton模式的主要作用是在Java应用程序中保证一个类Class只有一个实例存在。

在需要进行单线程操作的场景中,例如建立目录或数据库连接,或者管理内部和外部资源时,单例模式尤为重要。

外部资源管理的例子包括:每台计算机可以有多个打印机,但只能有一个Printer Spooler,以防止两个打印作业同时输出到打印机。

同样,每台计算机可以有多个通信端口,系统应当集中管理这些端口,以防止一个端口被两个请求同时调用。

内部资源管理的例子包括:大多数软件系统都有一个或多个属性文件存放系统配置,这些属性文件应当由一个对象来管理。

例如,Windows回收站只能有一个实例,整个系统都使用这个唯一的实例,而回收站自行提供自己的实例。

因此,回收站是单例模式的一个典型应用。

单例模式有两种实现形式:1. 饿汉式单例类javapublic class Singleton {private Singleton() {} // 私有构造函数,只供内部调用private static Singleton instance = new Singleton(); // 静态实例public static Singleton getInstance() { // 提供静态方法供外部访问return instance;}}2. 懒汉式单例类javapublic class Singleton {private static Singleton instance = null; // 延迟初始化public static synchronized Singleton getInstance() {if (instance == null) {instance = new Singleton(); // 第一次调用时创建实例}return instance;}}懒汉式单例类的特点是延迟初始化,即第一次调用时才创建实例,后续调用不再重复创建,提高了效率。

你可能想看:
« 上一篇
下一篇 »

相关推荐

php实时推送,php实地培训

2026年10月05日

53阅读

php乱码出现问号的原因,php乱码出现问号的原因有哪些

2026年10月05日

44阅读

php一句话木马,一句话木马ctf

2026年10月05日

48阅读

php获取数组长度,php中如何获取数组的长度

2026年10月05日

50阅读

php面试题库及答案,php程序员面试真题库

2026年10月05日

47阅读

phpcontent-type修改,php源码二次修改需要多少钱

2026年10月05日

42阅读