6-单例模式

单例模式

典型实例:电脑的任务管理器

详细参考:单例模式 | 菜鸟教程 (runoob.com)

关键:\textcolor{red}{关键:}构造函数私有化

提示:12月7日下周周三上实验课
适合使用单例模式的2种类
  1. 占用资源特别多的类(特别占内存)

  2. 起管理作用的类

单例模式的定义

image-20221128190958385

对象创建型模式

  • 某个类只能有一个实例
  • 必须自行创建这个实例
  • 必须自行向整个系统提供这个实例

如果单例类有重载构造函数,需要将所有的构造函数都设为私有的(private)。

单例模式结构

image-20221128191339642
  1. 构造函数私有化

  2. 私有静态成员变量存储实例

  3. 静态public方法返回私有实例

要点:
  1. 私有构造函数

  2. 静态私有成员变量(自身类型)

  3. 静态公有的工厂方法

核心代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Singleton {
private static Singleton instance=null; //静态私有成员变量

//私有构造函数
private Singleton() {
}

//静态公有工厂方法,返回唯一实例
public static Singleton getInstance() {
if(instance==null)
instance=new Singleton();
return instance;
}
}

单例模式只能有一个单例角色:

image-20221128191817487

Load Balancer:负载均衡器,判断服务器是否空闲并分配请求。

负载均衡软件:确保一个计算机只能启动一个负载均衡软件,避免发生冲突。

实例类图:
image-20221128192828984

服务器负载均衡器结构图

image-20221128192836158
存在问题:

当多线程开发时,可能会出现new出多个单例类,因此不能保证唯一性。

单例模式的六种实现方法

1️⃣饿汉式单例

饿汉式单例类(Eager Singleton)结构图
image-20221128193745858
饿汉式单例类(Eager Singleton)核心代码
1
2
3
4
5
6
7
8
public class EagerSingleton { 
private static final EagerSingleton instance = new EagerSingleton();
private EagerSingleton() { }
 
public static EagerSingleton getInstance() {
return instance; //定义的属性instance在此注入,符合聚合关系
}
}

==关键:==不管客户端需不需要,EagerSingleton类先实例化了类的对象

启动一个虚拟机时会调用Runtime类

懒汉式单例

懒汉式单例类(Lazy Singleton)结构图
image-20221128194200875
2️⃣延迟加载(Lazy Load):基础版
1
2
3
4
5
6
7
8
9
10
11
12
public class LazySingleton { 
private static LazySingleton instance = null;

private LazySingleton() { }

public static LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
3️⃣延迟加载(Lazy Load):改进版之锁方法
1
2
3
4
5
6
7
8
9
10
11
12
public class LazySingleton { 
private static LazySingleton instance = null;

private LazySingleton() { }

synchronized public static LazySingleton getInstance() { //加锁,但是锁住了对象导致性能下降
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
4️⃣延迟加载(Lazy Load):改进版之锁代码段
1
2
3
4
5
6
7
8
9
10
11
12
13
……
public static LazySingleton getInstance() {
if (instance == null) {
synchronized (LazySingleton.class) { //锁住代码片段,但是白锁
instance = new LazySingleton();
}
}
return instance;
}
……
/**
*白锁,多线程时可能会有两个及以上的线程都进入了if语句中,当一个线程创建完之后会解除锁,这时另一个线程会继续执行创建实例的代码,所以需要在锁之后再加上判断instance == null的代码
*/
5️⃣延迟加载(Lazy Load):改进版之双重检查锁定
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class LazySingleton { 
private volatile static LazySingleton instance = null;
private LazySingleton() { }
public static LazySingleton getInstance() {
//第一重判断-锁代码之前先判断一次
if (instance == null) {
//锁定代码块
synchronized (LazySingleton.class) {
//第二重判断-返回实例之前再判断一次
if (instance == null) {
instance = new LazySingleton(); //创建单例实例
}
}
}
return instance;
}
}

volatile:是Java提供的一种轻量级的同步机制。Java 语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量,相比于synchronized(synchronized通常称为重量级锁),volatile更轻量级,因为它不会引起线程上下文的切换和调度。但是volatile 变量的同步性较差(有时它更简单并且开销更低),而且其使用也更容易出错。

饿汉式单例与懒汉式单例的比较

  1. 饿汉式单例类:无须考虑多个线程同时访问的问题;调用速度和反应时间优于懒汉式单例;资源利用效率不及懒汉式单例;系统加载时间可能会比较长

  2. **懒汉式单例类:**实现了延迟加载;必须处理好多个线程同时访问的问题;需通过双重检查锁定等机制进行控制,将导致系统性能受到一定影响

6️⃣静态内部类实现单例模式(限Java)——IoDH

1
2
3
4
5
6
7
8
9
10
11
12
//Initialization on Demand Holder
public class Singleton {
private Singleton() {
}
//静态内部类
private static class HolderClass {
private final static Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return HolderClass.instance;
}
}

优点:

  1. 只有在调用getInstance方法返回内部类实例的时候才会为内部类分配内存,不会影响性能。
  2. 虚拟机会在创建内部类实例的时候自动为其加上锁,确保只能有一个线程访问,保证内部类的线程安全。

模式优点

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

  2. 可以节约系统资源,提高系统的性能

  3. 允许可变数目的实例(多例类

    • 多例:指定单例数量(种类)(可以指定i变量通过getInstance(int i)方法创建指定特征的单例实例)
    • 多例模式是单例模式的扩展

模式缺点

  1. 扩展困难缺少抽象层

  2. 单例类的职责过重

    • 违背单一职责原则
  3. 可能会导致共享的单例对象的状态丢失

    • 一个客户端对单例对象的修改会影响到所有使用该单例对象的客户端。

模式适用环境

  • 系统只需要一个实例对象,或者因为资源消耗太大而只允许创建一个对象

  • 客户调用类的单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途径访问该实例

多例模式

设计一个多例类(Multiton),包含指定数量的实例。

image-20221128201942212 image-20221128201929796

多例模式:可以指定i变量通过getInstance(int i)方法创建指定特征的单例实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//Initialization on Demand Holder
public class Singleton {
private Singleton() {
}
//静态内部类
private static class HolderClass {
private final static Singleton instance = new Singleton();
}
public static Singleton getInstance(int i) {
//i=0
return 对应特征单例实例……
//i=1
return 对应特征单例实例……
//i=2
return 对应特征单例实例……
//return HolderClass.instance;
}
}
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2023-2024 Guijie Wang
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信