那些超经典的设计模式—单例模式

好记忆不如烂笔头,能记下点东西,就记下点,有时间拿出来看看,也会发觉不一样的感受.

单例设计模式是java中非常经典的设计模式,如下将好好讲解下java设计模式相关的知识。
 

1. 单例设计模式的前世今生

起源与背景

单例模式(Singleton Pattern)是设计模式中最为简单的一种模式,属于创建型模式。它的核心思想是确保一个类只有一个实例,并提供一个全局访问点来获取这个实例。

在软件开发中,有些对象只需要一个实例,例如系统配置管理器、日志记录器、线程池等。如果这些对象被多次实例化,可能会导致资源浪费或逻辑冲突。因此,单例模式应运而生,用于解决这类问题。

发展历程
  • 早期实现:在 Java 的早期版本中,单例模式的实现主要依赖于私有化构造函数和静态方法。通过将构造函数设置为私有,防止外部直接实例化对象,再通过静态方法提供一个全局访问点。

  • 线程安全问题:随着多线程编程的发展,单例模式的线程安全性问题逐渐暴露。如果多个线程同时调用单例的获取方法,可能会导致多个实例被创建。因此,引入了同步机制(如 synchronized)来解决这一问题。

  • 性能优化:使用同步方法虽然解决了线程安全问题,但可能会带来性能瓶颈。因此,出现了双重检查锁定(Double-Check Locking)和初始化按需持有类(Initialization-on-demand Holder)等优化方式。

  • 现代实现:在 Java 5 之后,引入了 enum 枚举来实现单例模式,这种方式不仅简单,而且天然线程安全,成为一种推荐的实现方式。

2. 单例设计模式的使用场景

单例模式适用于以下场景:

资源共享
  • 配置管理器:系统中通常只需要一个配置管理器实例来加载和管理配置信息,避免重复加载配置文件。

  • 日志记录器:日志记录器通常只需要一个实例,用于统一管理日志的输出,避免多个实例对日志文件的并发写入。

系统全局状态
  • 线程池:线程池通常只需要一个实例,用于管理线程资源,避免过多线程的创建和销毁。

  • 缓存管理器:缓存管理器通常只需要一个实例,用于管理缓存数据,避免多个实例之间的数据不一致。

性能优化
  • 数据库连接池:数据库连接池通常只需要一个实例,用于管理数据库连接资源,避免频繁创建和销毁连接。

  • 文件系统管理器:文件系统管理器通常只需要一个实例,用于管理文件资源,避免多个实例对文件系统的并发操作。

3. 单例设计模式的使用注意事项

线程安全
  • 同步机制:如果单例模式的实现中涉及到多线程环境,必须确保线程安全。可以使用 synchronized 同步方法或同步代码块来防止多个线程同时创建实例。

  • 双重检查锁定:在使用双重检查锁定时,必须将实例变量声明为 volatile,以防止指令重排序问题。

序列化问题
  • 反序列化:如果单例类实现了 Serializable 接口,反序列化时可能会创建新的实例。可以通过实现 readResolve() 方法来解决这一问题,确保反序列化时返回同一个实例。

序列化问题
  • 反射破坏:如果单例类的构造函数被反射调用,可能会破坏单例模式。可以通过在构造函数中添加额外的检查逻辑来防止反射破坏。

性能优化
  • 懒汉式加载:如果单例实例的创建开销较大,可以使用懒汉式加载(延迟初始化),但需要确保线程安全。

  • 饿汉式加载:如果单例实例的创建开销较小,可以使用饿汉式加载(在类加载时初始化),避免线程安全问题。

4. 单例模式的代码样例

以下是几种常见的单例模式实现方式及其代码样例:

饿汉式(线程安全,但可能浪费资源)
public class Singleton {
    private static final Singleton instance = new Singleton();

    private Singleton() {
        // 私有构造函数,防止外部实例化
        if (instance != null) {
            throw new IllegalStateException("Already initialized");
        }
    }

    public static Singleton getInstance() {
        return instance;
    }
}
懒汉式(线程安全,但性能较差)

public class Singleton {
    private static Singleton instance;

    private Singleton() {
        // 私有构造函数,防止外部实例化
        if (instance != null) {
            throw new IllegalStateException("Already initialized");
        }
    }

    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}
双重检查锁定(线程安全且性能较好)

public class Singleton {
    private static volatile Singleton instance;

    private Singleton() {
        // 私有构造函数,防止外部实例化
        if (instance != null) {
            throw new IllegalStateException("Already initialized");
        }
    }

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
初始化按需持有类(线程安全且性能较好)

public class Singleton {
    private Singleton() {
        // 私有构造函数,防止外部实例化
        if (Holder.INSTANCE != null) {
            throw new IllegalStateException("Already initialized");
        }
    }

    private static class Holder {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return Holder.INSTANCE;
    }
}
枚举实现(线程安全且简单)

public enum Singleton {
    INSTANCE;

    // 可以添加其他方法
    public void someMethod() {
        System.out.println("Singleton method called");
    }
}

总结

单例模式是一种简单而强大的设计模式,适用于需要全局唯一实例的场景。在使用单例模式时,需要注意线程安全、序列化和反射破坏等问题,并根据实际需求选择合适的实现方式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值