技术成神之路:设计模式(一)单例模式

简介: 【7月更文挑战第3天】技术成神之路:设计模式(一)单例模式

在软件设计中,有时我们希望某个类的实例始终是唯一的,即无论在何处访问这个类,都能够得到同一个实例。单例模式(Singleton Pattern)就是为了解决这个问题而产生的。单例模式确保一个类只有一个实例,并提供一个全局访问点。

1.定义
单例模式是一种创建型设计模式,确保一个类只有一个实例,并提供一个全局访问点来访问这个实例。其主要思想是将类的构造函数私有化,并通过一个静态方法来控制实例的创建和访问。

2.常见实现方式
单例模式有多种实现方式,下面介绍几种常见的实现方式:

2.1饿汉式(Eager Initialization)
饿汉式是在类加载时就创建实例,这样可以确保线程安全,并且在类首次使用前完成实例化。

示例代码:

public class Singleton {
private static final Singleton INSTANCE = new Singleton();

private Singleton() {
    // 私有构造函数,防止外部实例化
}

public static Singleton getInstance() {
    return INSTANCE;
}

}
1
2
3
4
5
6
7
8
9
10
11
优点:简单,易于理解,线程安全
缺点:类加载时即创建实例,可能造成资源浪费

如果你一定会使用该类,这种方式无疑是最简单的方法

2.2 懒汉式(Lazy Initialization)
懒汉式是在第一次调用 getInstance() 方法时创建实例。这种方式避免了饿汉式的资源浪费问题。

示例代码:

public class Singleton {
private static Singleton instance;

private Singleton() {
    // 私有构造函数,防止外部实例化
}

public static synchronized Singleton getInstance() {
    if (instance == null) {
        instance = new Singleton();
    }
    return instance;
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
优点:实现简单,延迟实例化,避免资源浪费
缺点:使用了 synchronized,在高并发情况下性能可能较差

每次调用getInstance()都会进行同步检查,这样会消耗不必要的资源,不推荐使用

2.3双重检查锁(Double-Checked Locking)
双重检查锁在懒汉式的基础上,通过减少使用 synchronized 来提高性能。

示例代码:

public class Singleton {
// volatile关键字确保多线程下的可见性和有序性(禁止字节码重排)
private static volatile Singleton instance;

private Singleton() {
    // 私有构造函数,避免外部直接实例化
}

public static Singleton getInstance() {
    if (instance == null) {  // 第一次检查
        synchronized (Singleton.class) {
            if (instance == null) {  // 第二次检查
                instance = new Singleton();  // 实例化
            }
        }
    }
    return instance;  // 返回实例
}

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
优点:延迟实例化,提高了性能
缺点:实现复杂,容易出错

同步代码块含义:因为可能会有多个线程同时通过了第一次检查,在进入同步块之后,再次检查可以确保只有一个线程创建实例,最大限度地在提升性能的条件下保证了线程安全。

emm… 个人不喜欢这种笨重写法

2.4 静态内部类(Static Inner Class)
这种方式使用了类加载机制来确保线程安全,同时实现了延迟加载。

示例代码:

public class Singleton {
private Singleton() {
// 私有构造函数,防止外部实例化
}

 // 静态内部类,利用类加载机制保证线程安全且延迟加载
private static class SingletonHolder {
    private static final Singleton INSTANCE = new Singleton();
}

public static Singleton getInstance() {
    return SingletonHolder.INSTANCE;
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
优点:延迟实例化,线程安全,实现简单
缺点:无法传递外部参数

这时候就会有同学要问了,何为类加载机制,问的好,所谓类加载机制就算:JVM 在加载类的过程中,静态内部类 SingletonHolder 中的静态变量 INSTANCE 只会被实例化一次,由JVM保证其线程安全性,所以在多线程环境下可以安全地使用。

2.5 枚举(Enum)
这种方法是Effective Java作者Joshua Bloch推荐的单例实现方式之一,它解决了传统单例模式实现中的一些问题,比如序列化、反射攻击等。

示例代码:

public enum Singleton {
INSTANCE;

public void doSomething() {
    // 业务方法
}

}
1
2
3
4
5
6
7
优点:简洁,线程安全,防止反序列化破坏单例
缺点:无法灵活控制实例化过程

使用方法:

Singleton.INSTANCE.doSomething();
1
特点和优势

线程安全性:
枚举类型的实例创建是线程安全的,JVM在加载枚举类型时会通过类加载器保证只实例化一次。因此,多线程环境下也能保证单例的唯一性。

防止反射攻击:
枚举类型的实例创建是由JVM控制的,因此无法通过反射来创建枚举类的实例。这样可以防止反射攻击,即使是在枚举类中添加了私有构造函数也不例外。

防止序列化问题:
Java枚举类型在序列化和反序列化时会自动处理,确保在序列化和反序列化过程中都是单例的。

简洁且高效:
枚举实现单例模式非常简洁,只需声明一个枚举类型即可,不需要额外的代码来保证线程安全和单例特性。

3.单例模式的注意事项
线程安全:确保在多线程环境下一个类只有一个实例。
延迟加载:尽量避免在类加载时就实例化,除非明确知道实例一定会被使用。
防止反射攻击:通过在构造函数中添加判断来防止反射创建多个实例。
防止反序列化破坏单例:在实现 Serializable 接口时,提供 `readResolve 方法。
4.总结
五种创建单例的方式,大家按需选择,核心思想都是确保一个类只有一个实例,并提供全局访问点,没有最好的,只有最适合的,理解不同实现方式的优缺点,可以帮助我们在实际开发中选择最合适的方案。

相关文章
|
1月前
|
设计模式 存储 SQL
PHP中的设计模式:单例模式的探索
在PHP开发中,单例模式是一种常用的设计模式,它确保一个类只有一个实例,并提供一个全局访问点。本文将通过一个简单的例子,逐步引导你理解如何在PHP中实现和利用单例模式,以及它在实际项目中的应用价值。
|
28天前
|
设计模式 物联网 Android开发
移动应用与系统:探索未来技术的融合之路后端开发中的设计模式探索
【8月更文挑战第21天】随着科技的飞速发展,移动应用和操作系统已经成为我们日常生活中不可或缺的一部分。本文将深入探讨移动应用开发和移动操作系统的相关话题,包括它们的历史、现状以及未来的发展趋势。我们将从移动应用的开发环境、编程语言和工具等方面进行详细的分析,同时也会讨论移动操作系统的特点、优势以及面临的挑战。最后,我们将展望移动应用与系统在未来技术融合中的可能方向和机遇。
123 58
|
30天前
|
设计模式 存储 负载均衡
【五】设计模式~~~创建型模式~~~单例模式(Java)
文章详细介绍了单例模式(Singleton Pattern),这是一种确保一个类只有一个实例,并提供全局访问点的设计模式。文中通过Windows任务管理器的例子阐述了单例模式的动机,解释了如何通过私有构造函数、静态私有成员变量和公有静态方法实现单例模式。接着,通过负载均衡器的案例展示了单例模式的应用,并讨论了单例模式的优点、缺点以及适用场景。最后,文章还探讨了饿汉式和懒汉式单例的实现方式及其比较。
【五】设计模式~~~创建型模式~~~单例模式(Java)
|
1月前
|
设计模式 安全 程序员
C#设计模式之单例模式
C#设计模式之单例模式
39 3
|
27天前
|
设计模式 SQL 缓存
Java编程中的设计模式:单例模式的深入理解与应用
【8月更文挑战第22天】 在Java的世界里,设计模式是构建可维护、可扩展和灵活的软件系统的基石。本文将深入浅出地探讨单例模式这一经典设计模式,揭示其背后的哲学思想,并通过实例演示如何在Java项目中有效运用。无论你是初学者还是资深开发者,这篇文章都将为你打开一扇洞悉软件设计深层逻辑的大门。
26 0
|
1月前
|
设计模式 存储 数据库连接
Python设计模式:巧用元类创建单例模式!
Python设计模式:巧用元类创建单例模式!
31 0
|
1月前
|
设计模式 安全 测试技术
[设计模式]创建型模式-单例模式
[设计模式]创建型模式-单例模式
|
2月前
|
设计模式 安全 C++
C++一分钟之-C++中的设计模式:单例模式
【7月更文挑战第13天】单例模式确保类只有一个实例,提供全局访问。C++中的实现涉及线程安全和生命周期管理。基础实现使用静态成员,但在多线程环境下可能导致多个实例。为解决此问题,采用双重检查锁定和`std::mutex`保证安全。使用`std::unique_ptr`管理生命周期,防止析构异常和内存泄漏。理解和正确应用单例模式能提升软件的效率与可维护性。
32 2
|
2月前
|
设计模式 安全 Java
Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
60 1
|
2月前
|
设计模式 数据采集 监控
iLogtail设计模式问题之单例模式主要适用于什么场景
iLogtail设计模式问题之单例模式主要适用于什么场景