面试题答案
一键面试1. 饿汉式
- 内存管理与垃圾回收影响:
- 在类加载时就创建实例,只要类被加载到内存,实例就一直存在,不会被垃圾回收。这种方式简单直接,不存在多线程安全问题,因为类加载机制本身是线程安全的。
- 导致内存泄漏或不必要开销情况:
- 如果该单例实例在整个应用生命周期中很少甚至从未使用,会造成内存浪费,但不会导致内存泄漏。因为实例被正常持有,只是未被有效利用。
- 解决建议:
- 若确定实例会被频繁使用,饿汉式是不错选择。若实例使用频率不确定,可考虑其他延迟加载的单例模式。
2. 懒汉式(线程不安全)
- 内存管理与垃圾回收影响:
- 实例在第一次使用时才创建,在未创建前不占用额外内存。但由于线程不安全,在多线程环境下可能创建多个实例,增加内存开销。
- 导致内存泄漏或不必要开销情况:
- 多线程并发访问时,可能创建多个实例,这些额外的实例若不能被正确回收,会导致内存泄漏。
- 解决建议:
- 不要在多线程环境下使用这种简单的懒汉式。若要使用懒加载,可采用线程安全的懒汉式(如同步方法或双重检查锁)。
3. 懒汉式(线程安全,同步方法)
- 内存管理与垃圾回收影响:
- 保证了线程安全,实例延迟创建。但每次调用
getInstance
方法都进行同步,性能较低,特别是在高并发环境下,大量线程等待锁,会造成不必要的CPU开销。
- 保证了线程安全,实例延迟创建。但每次调用
- 导致内存泄漏或不必要开销情况:
- 不必要的开销主要来自频繁的同步操作,而不会直接导致内存泄漏。
- 解决建议:
- 可以考虑更高效的同步策略,如双重检查锁,减少不必要的同步开销。
4. 双重检查锁
- 内存管理与垃圾回收影响:
- 实现了延迟加载且保证了线程安全。只有在实例未创建时才进行同步操作,提高了性能。由于是延迟加载,未使用时不占用额外内存。
- 导致内存泄漏或不必要开销情况:
- 在早期Java内存模型不完善时,存在指令重排序问题,可能导致在实例未完全初始化时就被其他线程访问,造成潜在问题,但Java 5之后通过
volatile
关键字解决了此问题。只要正确使用volatile
,一般不会导致内存泄漏或不必要开销。
- 在早期Java内存模型不完善时,存在指令重排序问题,可能导致在实例未完全初始化时就被其他线程访问,造成潜在问题,但Java 5之后通过
- 解决建议:
- 确保
instance
变量使用volatile
修饰,以防止指令重排序带来的问题。
- 确保
5. 静态内部类
- 内存管理与垃圾回收影响:
- 实现了延迟加载,且利用类加载机制保证线程安全。只有在调用
getInstance
方法时,静态内部类才会被加载并创建实例。在未加载静态内部类前,不占用额外内存。
- 实现了延迟加载,且利用类加载机制保证线程安全。只有在调用
- 导致内存泄漏或不必要开销情况:
- 正常情况下不会导致内存泄漏或不必要开销。但如果静态内部类持有外部类的引用,且外部类实例在不需要时无法被回收,可能导致内存泄漏。
- 解决建议:
- 确保静态内部类不持有外部类可能导致内存泄漏的引用。如果必须持有,要在合适时机释放引用。