Java设计模式-单例模式(java单例模式原理)
单例模式定义:它确保一个类只有一个实例,并提供一个全局访问点来访问该实例。
单例模式主要分为两大类:饿汉式和懒汉式,懒汉式又分为 单线程下的普通懒汉式,多线程下的双重校验锁、静态内部类、枚举。
单例模式的应用场景举例:
配置管理器:当应用程序需要读取和维护配置信息时,通常会使用单例模式来创建一个配置管理器。这保证了整个应用中只有一份配置数据副本,所有组件都引用同一个配置对象,从而避免了数据不一致的问题。
日志记录器:单例模式确保在整个应用程序中只有一个日志记录器实例。这样,所有的日志消息都可以统一地被这个实例处理。
单例模式确保在整个应用程序中只有一个日志记录器实例。这样,所有的日志消息都可以统一地被这个实例处理。例如,在 Java 中,java.util.logging.Logger类可以通过单例模式来实现。开发人员可以通过Logger.getLogger("name")方法获取一个唯一的日志记录器实例,所有对该实例的调用都可以保证日志的一致性,比如记录不同模块的信息到同一个日志文件中。
缓存:缓存数据通常需要全局唯一的实例来管理,以便在不同的地方访问和修改缓存时保持一致性。
单例模式可以用于实现缓存。一个单例的缓存实例可以存储经常访问的数据,在整个应用程序中共享。例如,一个 Web 应用中的用户权限缓存。当用户登录后,系统会查询数据库获取用户的权限信息并存储在单例缓存中。在用户后续的操作中,如访问某个需要权限验证的页面时,系统可以直接从这个单例缓存中获取用户权限信息,而不是每次都去查询数据库,大大提高了系统的响应速度。
数据库连接池:
数据库连接是一个昂贵的操作,频繁地创建和销毁连接会消耗大量的系统资源。因此,通常会使用连接池来管理数据库连接,而连接池本身往往是一个单例,以确保在整个应用中只有一个连接池实例,优化数据库访问性能。
线程池:
当处理大量并发任务时,为每个任务创建一个新线程会导致系统资源耗尽。线程池可以预先创建一组线程,任务到来时,将任务分配给线程池中的线程来执行,任务执行完毕后线程可以被复用。
单例模式适用于线程池的实现。整个应用程序通常只需要一个线程池来管理线程资源。例如,在 Java 的ExecutorService框架中,通过Executors.newFixedThreadPool(n)创建一个固定大小的线程池,这个线程池可以作为一个单例存在于应用程序中。所有需要异步执行的任务都可以提交给这个单例线程池,它可以有效地管理线程的创建、分配和回收,提高系统的并发处理能力。
单例模式的优点:
- 控制实例数量:确保一个类只有一个实例,避免了实例的重复创建,节省系统资源。
- 全局访问点:提供一个全局访问点,使得访问该实例变得简单。
- 延迟加载:某些实现方式(如懒汉式单例)可以实现延迟加载,即在需要时才创建实例,从而提高系统性能。
- 资源共享和节省:单例模式确保在整个应用程序中只有一个实例存在。对于一些资源密集型的对象,如数据库连接池、线程池等,这可以避免创建多个相同的对象,从而节省系统资源。
(一)单例模式-饿汉式java样例
public class Singleton {
// 1. 私有静态成员变量,直接创建实例对象
private static Singleton instance = new Singleton();
// 2. 私有构造方法,防止外部通过构造函数创建新的实例
private Singleton() {
}
// 3. 公共静态方法,用于获取单例实例
public static Singleton getInstance() {
return instance;
}
// 可以在这里添加单例对象的其他业务方法,比如下面这个简单示例方法
public void showMessage() {
System.out.println("这是饿汉式单例模式的示例消息");
}
}
(二)单例模式-单线程下-懒汉式java样例
public class LazySingleton {
// 声明一个静态变量来保存单例实例,初始值为null
private static LazySingleton instance;
// 将构造方法设为私有,防止外部通过构造方法创建新的实例
private LazySingleton() {
}
// 提供一个静态的公共方法来获取单例实例
public static LazySingleton getInstance() {
// 判断实例是否已经创建,如果没有则创建一个新的实例
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
/* 如果该对象被用于序列化,可以保证对象在序列化前后保持一致 */
private Object readResolve() {
return instance;
}
// 可以在这里添加其他需要的方法等,例如示例的一个简单方法
public void showMessage() {
System.out.println("这是懒汉式单例模式的示例方法。");
}
}
(三)单例模式-多线程下-双重校验锁java样例
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;
}
/* 如果该对象被用于序列化,可以保证对象在序列化前后保持一致 */
private Object readResolve() {
return instance;
}
// 可以在这里添加其他业务方法,比如示例的一个简单方法
public void doSomething() {
System.out.println("执行单例实例中的业务操作");
}
}
(四)单例模式-静态内部类
public class Singleton {
// 私有构造方法,防止外部通过构造方法创建实例
private Singleton() {
}
// 定义静态内部类,在内部类中创建单例实例
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
// 提供公共的静态方法获取单例实例
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
/* 如果该对象被用于序列化,可以保证对象在序列化前后保持一致 */
private Object readResolve() {
return getInstance();
}
// 可以在这里添加其他业务方法,例如下面这个简单示例方法
public void showMessage() {
System.out.println("这是单例模式中执行的操作。");
}
}
(五)单例模式-枚举
public enum SingletonEnum {
INSTANCE;
// 可以在这里定义单例对象需要的属性和方法
private String message = "这是枚举单例模式中的信息";
public String getMessage() {
return message;
}
public void setMessage(String newMessage) {
message = newMessage;
}
}