目录
了解单例模式:
单例模式是一种创建型设计模式,它确保类只有一个实例,并提供一个全局访问点问这个实例。这个访问点通常是一个静态方法或属性。
单例模式主要解决了一个全局使用的类频繁创建和销毁时所带来的性能问题以及多个实例存在时可能导致的状态不一致等问题。通过将其实例化过程控制在一个类中并向外界提供唯一的访问接口,可以避免这些问题的出现。
单例模式有很多种实现方式:
-
饿汉模式(Eager Initialization):在类加载时就进行对象的初始化,保证了线程安全性。缺点是无法延迟对象的创建时间,可能会浪费资源。
-
懒汉模式(Lazy Initialization):在第一次使用该对象时才进行对象的初始化,避免了不必要的对象创建,但是需要考虑线程安全问题。
-
双重检验锁模式(Double-Checked Locking):结合了饿汉模式和懒汉模式的优势,既能保证线程安全又能延迟对象的创建时间。
-
静态内部类模式(Static Inner Class):利用 Java 类加载机制,在调用静态内部类时才会装载并初始化该内部类,从而实现了“懒汉”式的延迟加载。
-
枚举单例模式(Enum Singleton):利用 Java 枚举类型特性,保证只有一个枚举对象被创建,并提供了线程安全性和防止反射攻击的机制。
其中我们最常用的为懒汉模式和饿汉模式两种实现方式.懒汉模式是在首次使用时才进行对象的初始化,而饿汉模式是在类被加载时就已经创建好对象。本篇文章就懒汉模式和饿汉模式进行深入讲解。
懒汉模式
什么是懒汉模式?
懒汉模式是单例模式的一种实现方式,它是在需要时再进行对象的创建,而不是像饿汉模式那样在类加载时就创建好对象。具体来说,只有在第一次使用该单例对象时才会进行初始化,之后所有的访问都会返回同一个实例。
懒汉模式的优点是在程序启动时不会占用过多的系统资源,避免了资源浪费;缺点是需要考虑线程安全问题,因为在多线程环境下可能会出现并发问题,需要使用同步机制来保证线程安全性。
懒汉模式的常见实现方式
-
简单懒汉模式:在
getInstance()
方法中使用 synchronized 关键字来保证线程安全性。 -
双重校验锁懒汉模式:在
getInstance()
方法中使用双重检查锁定的方式来提高性能。在多线程环境下还需要使用 volatile 关键字来保证 instance 对象正确初始化。 -
静态内部类懒汉模式:将单例对象的初始化放在静态内部类中,利用 Java 类加载机制实现延迟加载。该方式既能保证线程安全,又能提高性能。
诸多实现模式中,以简单懒汉模式最为常见也最为常用,简单懒汉模式实现方式如下:
public class Singleton {
private static Singleton instance;
private Singleton() { } //私有构造方法
public static synchronized Singleton getInstance() {
if (instance == null) { //判断对象是否已经创建,保证单例
instance = new Singleton();
}
return instance;
}
}
在上面的代码中,getInstance()
方法使用了双重检查锁定来确保线程安全。如果 instance
为 null
,则创建一个新的实例,然后将其赋值给 instance
变量。由于需要使用同步机制来避免多个线程同时调用 getInstance()
方法,因此性能可能会受到影响。
简单懒汉模式的优点是只在需要时才进行初始化,从而节省了内存空间。但是它也有一些缺点,例如需要使用同步机制来确保线程安全,从而影响性能。此外,简单懒汉模式还存在“双重检查锁定”的问题,需要特别注意。
相对于懒汉模式,饿汉模式的主要优点是线程安全性更好,因为在多线程环境下不需要使用同步机制来保证线程安全性。但是,饿汉模式可能会导致资源浪费,因为即使没有用到该实例,也会在程序启动时就进行了初始化。
需要注意的是,在某些情况下,如果 Singleton
类的实例化过程比较复杂或者耗时比较长,那么饿汉模式可能会影响应用程序的启动效率和性能。
饿汉模式
什么是饿汉模式?
饿汉模式是单例设计模式的一种实现方式,它通过在应用程序启动时立即创建一个类实例来实现单例模式。这意味着无论是否需要该实例,它都会在整个应用程序生命周期中存在并可供使用。它可以保证在应用程序启动时就创建并初始化了一个单例对象,并且该对象将在整个应用程序生命周期内存在。与懒汉模式不同,饿汉模式没有延迟加载实例。
饿汉模式只有一种实现方式,即在类加载时就创建了单例对象,保证整个应用程序生命周期内只存在一个实例。
饿汉模式的实现
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton() {
// 私有化构造方法,防止外部实例化该类
}
public static Singleton getInstance() {
return instance;
}
// 其他业务逻辑方法...
}
在上述示例中,Singleton 类的 instance 静态成员变量被初始化为 Singleton 的一个实例。由于该变量是静态的,因此只会在类加载时被初始化一次,并且由于使用了 private 访问修饰符,外界无法通过构造方法创建新的实例。而 getInstance() 方法则提供了获取实例的入口,这样其他对象就可以通过该方法获取到 Singleton 的唯一实例。
饿汉模式的优点是在多线程环境下能够保证单例对象的唯一性,因为在类加载时就已经创建了实例,不存在并发问题。同时,由于实例被立即创建并初始化,因此可以避免懒汉模式中由于延迟加载带来的性能问题。不过,饿汉模式的缺点是可能会造成资源浪费,因为在某些情况下,单例对象可能不需要被使用,但是仍然被创建了出来。此外,如果单例对象的初始化过程比较复杂或耗时,也会对应用程序的启动时间产生影响。
总结
单例模式是一种简单但十分实用的设计模式,可以避免多个实例引起的问题,提高程序效率和简化代码实。在实际应用中被广泛使用。但常用的懒汉模式和饿汉模式均有缺点,在实际应用中需要根据具体情况来选择适合的实现方式,并注意一些相关的问题。