面试题答案
一键面试保证线程安全的单例模式
- 使用双重检查锁定(Double-Checked Locking)
- 双重检查锁定机制可以在保证线程安全的同时,尽量减少不必要的同步开销。在第一次检查时,如果实例已经存在,就不需要进入同步块,从而提高性能。
- 代码示例(假设TypeScript运行在支持多线程的环境下,使用类似Java的同步语法模拟):
class Singleton {
private static instance: Singleton;
private constructor() {}
public static getInstance(): Singleton {
if (!Singleton.instance) {
synchronized(Singleton.class) {
if (!Singleton.instance) {
Singleton.instance = new Singleton();
}
}
}
return Singleton.instance;
}
}
- 使用静态初始化块
- 在类加载时就初始化单例实例,Java中类加载过程是线程安全的,TypeScript虽然原生不支持多线程,但假设在支持多线程环境下可类比。
- 代码示例:
class Singleton {
private static instance: Singleton = new Singleton();
private constructor() {}
public static getInstance(): Singleton {
return Singleton.instance;
}
}
性能优化
- 延迟初始化
- 使用双重检查锁定方式实现延迟初始化,只有在真正需要使用单例实例时才进行初始化,避免在程序启动时就初始化所有可能用到的单例,从而节省内存和启动时间。上述双重检查锁定的代码示例就是延迟初始化的一种实现。
- 减少同步开销
- 如双重检查锁定中,外层的非同步检查可以减少进入同步块的次数。只有在第一次检查发现实例为
null
时才进入同步块进行初始化,这样大部分情况下(实例已存在时)无需同步操作,提高了并发性能。
- 如双重检查锁定中,外层的非同步检查可以减少进入同步块的次数。只有在第一次检查发现实例为
- 使用静态常量优化访问
- 如果单例类中的静态成员是常量(即不会改变的值),可以将其定义为
const
。这样在编译时就会确定其值,访问时无需动态查找,提高访问效率。例如:
- 如果单例类中的静态成员是常量(即不会改变的值),可以将其定义为
class Singleton {
private static readonly CONSTANT_VALUE: number = 42;
// 其他代码...
}
在使用Singleton.CONSTANT_VALUE
时,由于是常量,访问速度会更快。