单例模式
单例模式是一种常见的设计模式,确保一个类只有一个实例,并提供一个全局访问点。下面是单例模式的几种实现方式,包括线程安全的实现和延迟加载。
1. 懒汉式单例(线程不安全)
这种方式在第一次调用 getInstance() 方法时才创建实例,但在多线程环境下不是线程安全的。
css
在public class Singleton {
private static Singleton instance;
// 私有构造函数,防止外部创建实例
private Singleton() {}
// 提供一个全局访问点
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton(); // 非线程安全
}
return instance;
}
}
2. 懒汉式单例(线程安全)
使用 synchronized 关键字来保证线程安全,但每次调用 getInstance() 都会加锁,性能较低。
java
public class Singleton {
private static Singleton instance;
// 私有构造函数,防止外部创建实例
private Singleton() {}
// 提供一个全局访问点
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton(); // 线程安全
}
return instance;
}
}
3. 饿汉式单例
在类加载时就创建实例,因此线程安全,但不支持延迟加载。
java
public class Singleton {
private static final Singleton instance = new Singleton();
// 私有构造函数,防止外部创建实例
private Singleton() {}
public static Singleton getInstance() {
return instance; // 线程安全
}
}
4. 双重检查锁定(推荐)
这种方式结合了懒汉式和饿汉式的优点,在保证线程安全的同时提高性能。
java
public class Singleton {
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;
}
}
5. 静态内部类单例
利用 Java 的类加载机制来实现延迟加载和线程安全。
java
在public class Singleton {
// 私有构造函数,防止外部创建实例
private Singleton() {}
// 静态内部类,只有在调用 getInstance() 时才会加载
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
// 提供一个全局访问点
public static Singleton getInstance() {
return SingletonHolder.INSTANCE; // 线程安全且延迟加载
}
}
单例模式(Singleton Pattern)是一种常见的设计模式,确保某个类在应用程序中只有一个实例,并且提供全局访问点。单例模式列出常用于以下场景:
- 数据库连接池
应用场景: 数据库连接池需要管理有限的数据库连接。为了避免每次数据库操作都创建和销毁连接,可以使用单例模式来确保连接池对象在应用程序中只有一个实例。
示例: 连接池管理类通常是一个单例,多个数据库操作共享同一个连接池实例,避免资源浪费。 - 日志记录器(Logger)
应用场景: 在大型应用中,日志记录是一项非常重要的工作。日志类通常是单例模式,因为日志记录是跨多个模块共享的,确保日志文件在整个应用中只有一个实例。
示例: 日志管理器类只需要一个实例,所有模块或线程都通过该实例记录日志,避免多次创建日志文件句柄。 - 配置管理(Configuration)
应用场景: 配置文件(如应用的全局设置、数据库配置等)通常是全局共享的。在应用启动时,加载配置文件后,整个应用会使用同一个配置实例。
示例: 配置管理类通常是单例,用来读取和维护配置项的状态,确保所有模块获取到的配置是一致的。 - 线程池(ThreadPool)
应用场景: 线程池用于管理应用中多个线程的创建、销毁和复用。由于线程池管理的是有限的资源,采用单例模式可以确保线程池在应用程序中只有一个实例。
示例: 线程池类通常是单例,确保所有线程的管理都集中在一个地方,避免多个线程池实例的资源浪费。 - 缓存(Cache)
应用场景: 缓存通常用于存储频繁访问的数据,以提高性能。全局缓存实例可以确保所有模块都可以共享缓存的数据,避免每次访问时重新创建缓存。
示例: 缓存管理类作为单例存在,维护缓存数据的存取,确保一致性和高效性。