单例设计模式(懒汉式和饿汉式区别)

本文详细介绍了单例设计模式的概念及其在确保对象唯一性与节省系统资源方面的作用。通过对比饿汉式与懒汉式的实现方式,阐述了两者在线程安全、效率以及实例化时机上的差异,旨在帮助开发者在实际应用中做出最优选择。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

单例设计模式:保证对象 唯一性,创建对象时只能初始化一次对象,以后将只能调用第一次创建的对象,日后都将不能再次创建对象。

 

单列设计模式动机:

对于一个软件系统的某些类而言,我们无须创建多个实例。举个大家都熟知的例子——Windows任务管理器,如图3-1所示,我们可以做一个这样的尝试,在Windows的“任务栏”的右键弹出菜单上多次点击“启动任务管理器”,看能否打开多个任务管理器窗口?如果你的桌面出现多个任务管理器,我请你吃饭,(注:电脑中毒或私自修改Windows内核者除外)。通常情况下,无论我们启动任务管理多少次,Windows系统始终只能弹出一个任务管理器窗口,也就是说在一个Windows系统中,任务管理器存在唯一性。为什么要这样设计呢?我们可以从以下两个方面来分析:其一,如果能弹出多个窗口,且这些窗口的内容完全一致,全部是重复对象,这势必会浪费系统资源,任务管理器需要获取系统运行时的诸多信息,这些信息的获取需要消耗一定的系统资源,包括CPU资源及内存资源等,浪费是可耻的,而且根本没有必要显示多个内容完全相同的窗口;其二,如果弹出的多个窗口内容不一致,问题就更加严重了,这意味着在某一瞬间系统资源使用情况和进程、服务等信息存在多个状态,例如任务管理器窗口A显示“CPU使用率”为10%,窗口B显示“CPU使用率”为15%,到底哪个才是真实的呢?这纯属“调戏”用户,给用户带来误解,更不可取。由此可见,确保Windows任务管理器在系统中有且仅有一个非常重要。

 

回到实际开发中,我们也经常遇到类似的情况,为了节约系统资源,有时需要确保系统中某个类只有唯一一个实例,当这个唯一实例创建成功之后,我们无法再创建一个同类型的其他对象,所有的操作都只能基于这个唯一实例。为了确保对象的唯一性,我们可以通过单例模式来实现,这就是单例模式的动机所在。


//饿汉式
class Single
{
  private static final Single s = new Single();
  private Single(){}
  public static Single getInstance()
  {
      return s;
  }
}

//懒汉式  //为了实例的延迟加载,如果多线程访问时会出现安全问题。可以用同步来解决。不过有些低效。用双重判断可以解决低效。

class Single {
  private static Single s = null;
  private Single(){}
  public static Single getInstance()
  {
       if(s==null)
          s = new Single();
       return s;
  }
}


解决低效率代码://延迟加载的单例设计模式示例标准规范。
class Single {
  private static Single s = null;
  private Single(){}
  public static Single getInstance()
  {
       if(s==null) //只判断一次将不在进来判断同步代码,加同步的时候使用的锁是该类所属的字节码文件对象。
     {

      synchronized(Sing.class) // 因为在静态方法中是无法使用this锁,所以只能使用该类所属的字节码文件对象(Sing.class)来作为锁。
       if(s==null)
          s = new Single();
       return s;
      }
  }
}

懒汉式和饿汉式区别:
饿汉式:
         public class Singleton{
             private static Singleton singleton = new Singleton ();
             private Singleton (){}
             public Singleton getInstance(){return singletion;}
        }
 
     懒汉式:
        public class Singleton{  //懒汉式在操作延迟加载时如果不加上synchronized会出现安全问题,懒汉式是一种延迟对象的加载。
             private static Singleton singleton = null;
             public static synchronized synchronized getInstance(){
                  if(singleton==null){
                      singleton = new Singleton();
                  }
                 return singleton;
             }
        }
 
     比较:
饿汉式是线程安全的,在类创建的同时就已经创建好一个静态的对象供系统使用,以后不在改变
懒汉式如果在创建实例对象时不加上synchronized则会导致对对象的访问不是线程安全的,懒汉式如果加上synchronized会导致低效。可以使用双重if语句判断来避免每次运行synchronized造

成的低效。
          
推荐使用第一种

<think>首先,用户的问题是:“我想了解单例模懒汉饿汉式区别以及instance关键字的使用。请问单例模 懒汉 vs 饿汉式 区别 instance关键字用法。” 关键点: - 解释单例模懒汉饿汉式区别。 - 解释instance关键字的使用。 从系统指令中: - 所有行内数学表达使用$...$格。 - 独立公使用$$...$$格并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识。 - 回答结构清晰,帮助用户逐步解决问题。 - 参考站内引用:[^1], [^2], [^3], [^4]。 站内引用是关于Java单例模的实现: - [^1]: 饿汉式单例模。 - [^2]: 懒汉单例模(普通懒汉)。 - [^3]: 懒汉单例模(线程不安全)。 - [^4]: 饿汉式单例模,包括代码解释。 我需要基于这些引用构建回答,但用户的问题是“instance关键字的使用”,在引用中,instance似乎是变量名或类名的一部分,不是Java关键字。在Java中,instance通常用于单例模中表示单例实例的变量名。 在引用中: - [^1]: private static SingleTon singleTon = new SingleTon(); - [^2]: private static LazyMan lazyMan; - [^3]: private static Singleton3 instanse; // 注意拼写错误,应该是instance - [^4]: private static Singleton person = new Singleton("xx"); 所以,instance在这里是成员变量的名称,代表单例实例。Java中没有instance关键字;它只是一个变量名。 用户可能误解了,或者是在问instance在单例模中的用法。 现在,构建回答结构: 1. 介绍单例模。 2. 解释饿汉式懒汉。 3. 比较它们的区别。 4. 解释instance变量(不是关键字)的使用。 5. 生成相关问题。 使用中文回答。 步骤: - 清晰结构:分步骤或分节。 - 引用相关段落:自然地添加引用标识。 - 生成相关问题:在最后添加§§相关问题§§部分。 详细内容: 1. **单例模简介**:单例模确保一个类只有一个实例,并提供一个全局访问点。常用于资源管理、配置对象等。 2. **饿汉式**: - 在类加载时就创建实例。 - 优点:线程安全,因为实例在类初始化时创建。 - 缺点:可能造成资源浪费,如果实例未被使用。 - 代码示例:参考[^1][^4]。 - 例如:private static Singleton instance = new Singleton(); // 在类加载时初始化 3. **懒汉**: - 在第一次使用时创建实例。 - 优点:延迟加载,节省资源。 - 缺点:普通懒汉线程不安全;需要同步机制来保证线程安全。 - 代码示例:参考[^2][^3]。 - 例如:private static Singleton instance; public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } 4. **区别**: - 初始化时机:饿汉式在类加载时初始化;懒汉在第一次调用getInstance()时初始化。 - 线程安全:饿汉式天生线程安全;懒汉需要额外处理(如synchronized或双重检查锁)。 - 性能:饿汉式可能浪费资源;懒汉有性能开销在同步上。 - 资源利用:懒汉更高效,如果实例不总是需要。 5. **instance变量**: - 不是Java关键字,而是单例模中用于存储单例实例的静态变量。 - 通常命名为instance,如private static Singleton instance; - 在getInstance()方法中访问初始化。 - 引用中使用了singleTon、lazyMan、instanse(拼写错误)、person等变量名,但概念相同。 6. **相关问题生成**: - 基于主题,如优化、线程安全、应用场景。 - 例如: 1. 如何实现线程安全的懒汉单例模? 2. 单例模在哪些场景下适用? 3. 饿汉式懒汉的性能比较如何? 确保LaTeX格:问题中没有数学表达,所以可能不需要,但如果有变量名,可以用$...$,如$instance$。 回答结构: - 开头:直接回答问题。 - 主体:分节解释。 - 结尾:生成相关问题。</think>### 单例模懒汉 vs 饿汉式 区别及instance用法详解 单例模是一种设计模式,确保一个类只有一个实例,并提供全局访问点。它常用于资源管理(如数据库连接池)或配置对象。下面我将逐步解释懒汉饿汉式区别,以及`instance`变量的用法(注意:`instance`不是Java关键字,而是单例模中用于存储实例的静态变量名)。 #### 1. **饿汉式单例模** 饿汉式在类加载时就创建实例,因此实例在程序启动时已存在。 **特点**: - **线程安全**:由于实例在类初始化时创建,多线程环境下无需额外同步。 - **资源消耗**:可能造成资源浪费,如果实例未被使用。 - **实现简单**:直接静态初始化变量。 代码示例(参考引用[^1][^4]): ```java public class Singleton { // 静态变量instance在类加载时初始化 private static Singleton instance = new Singleton(); // 私有构造器,防止外部创建实例 private Singleton() {} // 全局访问点,直接返回已创建的实例 public static Singleton getInstance() { return instance; } } ``` 在这个例子中,`instance`变量在类加载时被赋值为`new Singleton()`,确保任何时候调用`getInstance()`都返回同一个对象[^1][^4]。 #### 2. **懒汉单例模** 懒汉在第一次调用`getInstance()`方法时才创建实例,实现延迟加载。 **特点**: - **延迟初始化**:节省资源,实例只在需要时创建。 - **线程不安全风险**:普通实现中,多线程环境下可能导致多个实例被创建(需额外处理,如`synchronized`)。 - **性能开销**:同步机制可能影响性能。 代码示例(参考引用[^2][^3]): ```java public class Singleton { // 静态变量instance初始为null,延迟初始化 private static Singleton instance; private Singleton() {} // 第一次调用时创建实例(线程不安全) public static Singleton getInstance() { if (instance == null) { // 判断实例是否已存在 instance = new Singleton(); // 创建新实例 } return instance; } } ``` 这里,`instance`变量初始为`null`,在`getInstance()`中检查并初始化。但多线程下,多个线程可能同时进入`if (instance == null)`块,导致创建多个实例[^2][^3]。 #### 3. **懒汉 vs 饿汉式 关键区别** | 方面 | 饿汉式 | 懒汉 | |--------------|----------------------------------|----------------------------------| | **初始化时机** | 类加载时创建实例(立即加载) | 第一次调用`getInstance()`时创建(延迟加载) | | **线程安全** | 天生线程安全(无竞争条件)[^1] | 普通实现线程不安全;需同步机制(如双重检查锁)[^3] | | **资源效率** | 可能浪费资源(实例总被创建)[^4] | 更高效(实例按需创建)[^2] | | **性能** | 访问快(无同步开销) | 同步版本有性能开销 | | **适用场景** | 实例必定被使用且资源不敏感 | 实例可能不被使用或资源敏感 | #### 4. **instance变量的用法** 在单例模中,`instance`是一个静态变量(通常命名为`instance`或类似),用于存储类的唯一实例。它不是Java关键字,而是开发者的命名约定。 **核心用法**: - **声明**:定义为`private static`,确保全局唯一封装性(如`private static Singleton instance;`)。 - **初始化**: - 饿汉式:直接赋值(如`= new Singleton();`)。 - 懒汉:在`getInstance()`中延迟赋值。 - **访问**:通过`public static`方法(如`getInstance()`)返回`instance`,禁止外部直接访问。 在引用代码中,变量名有差异(如`singleTon`、`lazyMan`、`instanse`),但作用相同:持有单例实例[^1][^2][^3][^4]。 **注意事项**: - 变量名应清晰(如用`instance`),避免拼写错误(引用[^3]中误写为`instanse`)。 - 懒汉需处理线程安全,例如添加`synchronized`或使用双重检查锁。 #### 总结 - **选择建议**:如果资源充足且需线程安全,优先用饿汉式;如果需延迟加载,用懒汉并添加同步机制。 - **最佳实践**:在Java中,推荐使用枚举或静态内部类实现单例,以兼顾线程安全延迟加载。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值