2018-10-15 16:16阅读: 237评论: 0推荐: 0

创建型模式 - 单例模式(实例唯一的产品)

单例模式(Singleton Pattern)

意图

确保一个类有且仅有一个实例,并且为客户提供一个全局访问点。

特点

  • 优点
  1. 保证被访问资源对象在内存中只有一个实例,节约了系统内存资源,也避免了对资源多重占用;
  2. 封装了访问实例方法,提供全局访问点,严格控制客户的访问方式;
  3. 通常常驻内存,不会频繁创建/销毁,节约了系统开销;
  • 缺点
  1. 没有抽象层,难以扩展;
  2. 类的职责过重,往往一个单例负责所有与之相关功能,违背了类设计的“职责单一”原则;
  3. 单例如果持有context,容易造成内存泄漏;
  4. 全局共享一个实例资源,难以隔离问题,进行单独测试;

适用场景

1)全局随时可能需要访问,访问方式复杂,而且资源受限;
2)需要常驻内存,避免频繁创建、销毁的资源;

通用UML类图

单例模式的8种写法与多线程

单例模式为了不让外部随意构建实例,一般需要将构造函数声明为private,在获取实例对象时,就无法通过动态函数来读取(因为此时实例还未初始化),故只能通过类方法(static方法)来获取实例引用。

  1. 饿汉式 静态常量 立即加载
    特点:简单,类装载时完成初始化,不存在多线程同步问题;
    优点:没有延迟实例化,如果程序一直没有使用,会造成资源浪费;
// Singleton.java
// 饿汉式 静态常量
public class Singleton {
    private final static Singleton INSTANCE = new Singleton();
     
    private Singleton() {   }
    public static Singleton getInstance() { return INSTANCE; }
     
    public void displaySingleton(){
        System.out.println("单例初始化方式: 饿汉式 静态常量");
    }
}
  1. 饿汉式 静态代码块 立即加载
    与饿汉式 静态常量类似,只是把实例初始化放在了类的静态代码块中,而非放在实例引用定义处。
// Singleton1.java
// 饿汉式 静态代码块
public class Singleton1 {
    private static Singleton1 instance;
     
    static{
        instance = new Singleton1();
    }
     
    private Singleton1(){}
    
    public static Singleton1 getInstance(){
        return instance;
    }
     
    public void displaySingleton(){
        System.out.println("单例初始化方式: 饿汉式 静态代码块");
    }
}
  1. 懒汉式 延迟加载 线程不安全
    如果在执行多个线程同时执行到instance == null,就会造成多次实例化。只适合单线程情况使用。
// Singleton2.java
// 懒汉式 延迟实例化 线程不安全
public class Singleton2 {
    private static Singleton2 instance;
    
    private Singleton2(){}
    
    public static Singleton2 getInstance(){
        if(instance == null){
            instance = new Singleton2();
        }
        return instance;
    }
}
  1. 懒汉式 延迟加载 线程安全(同步方法)
    效率低下,每次线程通过getInstance获取实例,甚至在对象已经实例化后,都要先等待别的线程释放资源。
// Singleton3.java
// 懒汉式 延迟实例化 线程安全(同步方法)
public class Singleton3 {
    private static Singleton3 instance;
     
    private Singleton3(){}
     
    public static synchronized Singleton3 getInstance(){
        if(instance == null){
            instance = new Singleton3();
        }
        return instance;
    }
     
    public void displaySingleton(){
        System.out.println("Singleton3单例初始化方式: 懒汉式 延迟实例化 线程安全(同步方法)");
    }
}
  1. 懒汉式 延迟实例化 线程安全(同步代码块)
    效率比4(同步方法)高,但是多线程可能会出现多次实例化的问题。
//Singleton4.java
//懒汉式 延迟实例化 线程安全(同步代码块)
public class Singleton4 {
    private static Singleton4 instance;
    private Singleton4(){}
     
    public static Singleton4 getInstance(){
        if(instance == null) {
            synchronized (Singleton4.class) {
                instance = new Singleton4();
            }
        }
         
        return instance;
    }
     
    public void displaySingleton(){
        System.out.println("Singleton4单例初始化方式: 懒汉式 延迟实例化 线程安全(同步代码块)");
    }
}
  1. 懒汉式 线程安全(双重检查)
    综合了4,5即线程安全(同步方法)和线程安全(同步代码块)的优缺点,解决了4的低效问题,又解决了5的多次实例化不安全问题。
// Singleton5.java
// 懒汉式 线程安全(双重检查)
public class Singleton5 {
    private static Singleton5 instance;
     
    private Singleton5(){}
     
    public static Singleton5 getInstance(){
        if(instance == null){
            synchronized(Singleton5.class){
                if(instance == null) {
                    instance = new Singleton5();
                }
            }
        }
        return instance;
    }
     
    public void displaySingleton(){
        System.out.println("Singleton5单例初始化方式: 懒汉式 线程安全(双重检查)");
    }
}
  1. 静态内部类
    与饿汉式类似,都是通过类的装载机制来初始化实例,不过,既解决了饿汉式无法延迟实例化的问题,又解决了线程安全的问题。
// Singleton6.java
// 静态内部类
public class Singleton6 {
    private Singleton6(){}
     
    private static class SingletonInstance{
        private static final Singleton6 INSTANCE = new Singleton6();
    }
     
    public static Singleton6 getInstance(){
        return SingletonInstance.INSTANCE;
    }
     
    public void displaySingleton(){
        System.out.println("Singleton6单例初始化方式: 静态内部类 线程安全");
    }
}
  1. 枚举类型
    通过枚举类型在构造的时候,被实例化。不仅能解决多线程问题,还能防止反序列化创建新的对象。JDK1.5之后才加入,现使用较少。
// Singleton7.java
// 枚举类型
public enum Singleton7 {
    INSTANCE;
    public void display(){
        System.out.println("Singleton7单例初始化方式: 枚举类型");
    }
}

总结

  1. 实现单例模式的核心在与私有化构造方法,在getInstance方法中读取实例引用。
  2. 如果是类加载时,就实例化,就成为饿汉式;否则,在getInstance方法中才实例化称为懒汉式。
  3. 各种实现方法比较
实现方法 特点 是否线程安全 是否推荐
饿汉式,静态常量 立即加载 可以用
饿汉式,静态代码块 立即加载 可以用
一般懒汉式 延迟加载 多线程不可用
懒汉式,同步方法 延迟加载,效率低 可以用,不推荐
懒汉式,同步代码块 延迟加载,多次实例化 不可用
懒汉式,双重验证 延迟加载,效率高 推荐
静态内部类 延迟加载,效率高 推荐
枚举类型 延迟加载,效率高,应用较少(>JDK1.5) 推荐

参考

  1. 设计模式之:创建型设计模式(6种), 博客园
  2. 单例模式的八种写法比较, 博客园

本文作者:明明1109

本文链接:https://www.cnblogs.com/fortunely/p/9785794.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   明明1109  阅读(237)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
历史上的今天:
2015-10-15 C 常用库函数memset,编译器宏定义assert
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.