单例模式
- 模式介绍:保证一个类仅有一个实例,并提供一个全局访问点来获取这个唯一的实例。
- 主要解决:一个全局使用的类频繁地创建与销毁。
- 关键代码:构造函数是私有的。
应用场景
- 数据库连接池:数据库连接是一种宝贵的资源,频繁地创建和销毁数据库连接会带来巨大的性能损耗。通过使用单例模式,可以确保整个应用程序中只有一个数据库连接池实例,这个实例负责维护和管理数据库连接,从而避免重复创建和销毁连接,提高数据库操作的效率。
- 缓存系统:在应用程序中,缓存系统是一个重要的组件,用于存储和快速访问常用的数据。通过使用单例模式,可以确保整个应用程序中只有一个缓存实例,这个实例负责存储和管理缓存数据,从而避免数据不一致和重复创建缓存对象的问题。
- 日志记录:在应用程序中,日志记录是一种常见的调试和错误追踪手段。为了确保日志信息的完整性和一致性,可以使用单例模式来创建一个日志记录类,确保整个应用程序中只有一个日志记录实例,这样所有的日志信息都会通过这个实例来记录和管理。
- 配置文件读取:配置文件通常包含应用程序的一些重要参数和设置,如数据库连接信息、API密钥等。为了方便地读取和管理这些配置信息,可以使用单例模式来创建一个配置管理类,确保整个应用程序中只有一个配置管理实例,这个实例负责读取和解析配置文件,并提供配置信息的访问接口。
- GUI组件:在图形用户界面(GUI)开发中,有些组件可能只需要一个实例就足够了,比如主窗口、对话框等。通过使用单例模式,可以确保在整个应用程序中只有一个这样的GUI组件实例,从而避免重复创建和显示相同的组件。
- 任务管理器、回收站等系统工具:在操作系统中,任务管理器、回收站等工具通常也采用单例模式实现。这是因为这些工具在整个系统运行过程中只需要一个实例就足够了,它们负责管理系统资源、监控进程和文件等任务。
- 网站计数器:在网站开发中,计数器用于记录网站的访问量、用户数量等信息。由于这些信息需要全局共享和实时更新,因此可以使用单例模式来创建一个计数器类,确保整个网站中只有一个计数器实例,从而避免数据不一致和重复计算的问题。
- 全局状态管理:在需要共享全局状态或数据的场景中,可以使用单例模式来创建一个全局状态管理类。这个类负责管理和维护全局状态或数据,并提供访问和修改这些状态或数据的接口。这样,在不同的地方就可以方便地访问和修改全局状态或数据了。
代码实现
1、懒汉式,线程不安全
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
2、懒汉式,线程安全
描述:这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步。优点:第一次调用才初始化,避免内存浪费。缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。getInstance() 的性能对应用程序不是很关键(该方法使用不太频繁)。
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
3、饿汉式
描述:这种方式比较常用,但容易产生垃圾对象。优点:没有加锁,执行效率会提高。缺点:类加载时就初始化,浪费内存。
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
4、双检锁/双重校验锁(DCL,即 double-checked locking)
描述:这种方式采用双锁机制,安全且在多线程情况下能保持高性能。getInstance() 的性能对应用程序很关键。
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}