您的位置:首页 > 文旅 > 旅游 > 东莞seo网络推广_电商要多少钱才可以做_优化网站技术_深圳网站建设运营

东莞seo网络推广_电商要多少钱才可以做_优化网站技术_深圳网站建设运营

2025/1/16 7:50:48 来源:https://blog.csdn.net/qq_35842623/article/details/145115874  浏览:    关键词:东莞seo网络推广_电商要多少钱才可以做_优化网站技术_深圳网站建设运营
东莞seo网络推广_电商要多少钱才可以做_优化网站技术_深圳网站建设运营

懒汉式单例是一种在需要时才会初始化实例的单例模式实现方式,适用于需要延迟加载的场景。以下是一个实际使用懒汉式单例的例子,并结合适用场景进行解析。


示例场景:日志管理器

在开发过程中,日志记录是一个常见需求,通常日志记录器在整个应用中只需要一个实例。使用懒汉式单例可以确保日志管理器只在第一次需要时进行初始化,从而节省系统资源。

懒汉式单例完整代码
public class LogManager {// 1. 静态变量,保存唯一实例,但不立即初始化private static LogManager instance = null;// 2. 私有构造方法,防止外部实例化private LogManager() {System.out.println("LogManager initialized!");}// 3. 提供一个静态方法访问唯一实例public static synchronized LogManager getInstance() {if (instance == null) {instance = new LogManager();  // 延迟实例化}return instance;}// 4. 示例方法,用于记录日志public void log(String message) {System.out.println("Log: " + message);}
}

代码解析

  1. 静态变量 instance

    • 静态变量 instance 用于保存 LogManager 类的唯一实例。
    • 初始值为 null,实例化操作延后到第一次调用 getInstance() 时才进行。
  2. 私有构造方法:

    • 构造方法被声明为 private,防止外部通过 new LogManager() 创建实例。
    • 在构造方法中可以放置初始化逻辑,例如配置日志文件路径等。
  3. 静态方法 getInstance()

    • 是懒汉式单例的核心,通过 synchronized 关键字保证线程安全。
    • 第一次调用时,instancenull,会创建一个新的实例;
      后续调用时,直接返回已经创建的实例。
  4. 功能性方法 log()

    • 提供具体的业务功能,例如记录日志。

使用示例

假设我们需要记录一些重要的操作日志,可以通过以下代码来使用 LogManager

public class Main {public static void main(String[] args) {// 第一次调用时实例化 LogManagerLogManager logger1 = LogManager.getInstance();logger1.log("This is the first log message.");// 第二次调用时直接返回已有实例LogManager logger2 = LogManager.getInstance();logger2.log("This is the second log message.");// 比较两个实例System.out.println("Are logger1 and logger2 the same instance? " + (logger1 == logger2));}
}

输出结果

LogManager initialized!
Log: This is the first log message.
Log: This is the second log message.
Are logger1 and logger2 the same instance? true
说明:
  • 第一次调用 LogManager.getInstance() 时,LogManager 被初始化(输出 "LogManager initialized!")。
  • 第二次调用 getInstance() 时,只是返回已有实例,没有再次创建新实例。
  • 比较两个实例,结果为 true,表明它们是同一个对象。

懒汉式单例的优缺点

优点
  1. 延迟加载
    • 实例在第一次使用时才创建,节省内存和系统资源。
  2. 线程安全性
    • 使用 synchronized 保证线程安全。
缺点
  1. 性能问题
    • 每次调用 getInstance() 都需要进入同步块,会带来一定的性能开销。在性能敏感的场景下可能不够高效。

改进方案:双重检查锁定(Double-Checked Locking)

为了解决同步带来的性能问题,可以使用双重检查锁定优化懒汉式单例:

public class LogManager {// 1. 静态变量,使用 volatile 修饰以保证可见性private static volatile LogManager instance = null;// 2. 私有构造方法private LogManager() {System.out.println("LogManager initialized!");}// 3. 提供静态方法,使用双重检查锁定public static LogManager getInstance() {if (instance == null) { // 第一次检查synchronized (LogManager.class) {if (instance == null) { // 第二次检查instance = new LogManager();}}}return instance;}// 示例功能public void log(String message) {System.out.println("Log: " + message);}
}
优势
  • 第一次检查和第二次检查减少了不必要的同步,提高了性能。
  • 使用 volatile 关键字保证多线程环境下的可见性,防止指令重排序导致的错误。
扩展1 — 双重检查锁定

这段代码是一个双重检查锁定(Double-Checked Locking)实现的懒汉式单例模式的核心部分,它旨在解决多线程环境下单例实例创建的线程安全问题,同时优化性能。下面是对这段代码的详细解析:

  1. 第一次检查 (if (instance == null)):

    • 目的:快速判断实例是否已经创建。
    • 优点:如果实例已经存在,则可以直接返回实例,避免进入同步块,提高了性能。
  2. 同步块 (synchronized (LogManager.class)):

    • 目的:保证在多线程环境下只有一个线程能够进入块内创建实例,确保线程安全。
    • synchronized用在类对象上,确保同一时刻只有一个线程可以初始化实例。
  3. 第二次检查 (if (instance == null)):

    • 目的:在同步块内再次检查实例是否为 null
    • 原因:在第一次检查之后进入同步块之前,可能有其他线程已经创建了实例,因此需要再次检查以防止重复创建。
  4. 实例化 (instance = new LogManager()):

    • 当且仅当 instance 确实为 null 且当前线程获得了同步锁时,才创建实例。
    • 确保 LogManager 的实例只被创建一次。
  5. 返回实例 (return instance):

    • 无论是通过快速路径(无锁)还是同步路径(加锁),最终都会返回唯一的实例。

Why Double-Checked Locking?

  • 性能优化

    • 通过双重检查,减少了进入同步锁的次数。只有在 instancenull 时,才会进入同步块。一般情况下(即实例已经创建后),只需要执行第一次检查即可返回实例,无需同步。
  • 线程安全

    • 同步块保证了只有一个线程可以执行实例初始化。即使多个线程同时发现 instancenull,由于同步的存在,最终只有一个线程能够创建实例。
扩展2 — 使用 volatile

为了完全保证双重检查锁定的正确性,instance 应该使用 volatile 关键字声明:

private static volatile LogManager instance = null;
  • 作用
    • 防止指令重排序1:确保 new LogManager() 操作的顺序正确,即先分配内存,再执行构造函数,最后将内存地址赋值给 instance
    • 变量在多个线程之间的可见性:一旦一个线程修改了 instance,其他线程能够立即看到变化。

双重检查锁定模式是实现懒汉式单例的一种高效方式,适用于性能要求较高的多线程环境。但是,它的正确实现依赖于 volatile 关键字来防止重排序问题。通过这种方式,我们可以在保证线程安全的同时,尽量减少同步带来的性能损耗。


总结

懒汉式单例适合于需要延迟加载且实例化成本较高的场景(如日志管理器、配置加载器等)。在并发场景下,最好使用线程安全的实现,例如同步方法版或双重检查锁定版,以确保唯一实例的正确性和性能的平衡。


  1. 指令重排序:编译器和处理器在执行程序时可能会对指令进行重排序,以优化性能。volatile 关键字会禁止这种重排序,确保变量的初始化和其他操作的执行顺序符合程序的预期。
    这对于实现线程安全的懒汉式单例模式非常重要,因为它保证了对象在初始化完成后才会被其他线程看到。 ↩︎

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com