问题

    有很多时候我们希望一个类,在代码中最多只有一个实例,例如太阳系中的太阳,我们希望太阳只有一个,那么怎么防止别人对太阳这个类实例化出第二个对象呢?这就要用到——单例模式

定义

    单例模式(Singleton),顾名思义,单例即单一的实例,确切地讲就是指在某个系统中只存在一个实例,同时提供集中、统一的访问接口,以使系统行为保持协调一致。

    单例模式保证了在程序的不同位置都可以且仅可以取到同一个对象实例:如果实例不存在,会创建一个实例;如果已存在就会返回这个实例。因为单例是一个类,所以你也可以为其提供相应的操作方法,以便于对这个实例进行管理。

    具体到项目中,我能想到的常见的应用场景是:管理全局变量,比如配置信息等…….

单例模式——饿汉模式(用的更多)

    所谓饿汉,即看到事物就立马狼吞虎咽。

    饿汉模式,即在类加载过程中就完成类的实例化,创建一个对象,使用该类的代码无法创建对象,只能获取这个对象。

示例代码:

1
2
3
4
5
6
7
8
9
10
11
class Sun {
private static final Sun sun = new Sun();
//构造方法私有化
private Sun(){

}
//公有静态方法,返回实例对象
public static Sun getInstance() {
return sun;
}
}

饿汉模式的缺点

    类加载过程中就完成类的实例化,但是如果在相当长的一段时间内没有用到这个对象,那这个对象在这段时间内占据内存,就会造成一定的内存资源浪费。

    能否在要使用时再创建对象呢?能,这就要用到懒汉模式

单例模式——懒汉模式

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Sun {
//不进行实例化
private static Sun sun;
//构造方法私有化
private Sun(){

}
//公有静态方法,返回实例对象
public static Sun getInstance() {
if (sun == null) {
//如果类没有实例化对象,才实例化
sun = new Sun();
}
return sun;
}
}

懒汉模式的改进

    在多线程情况下,上面的代码是不安全的,多个线程同时访问可能会实例化出多个对象,改进如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Sun {
//不进行实例化
private volatile static Sun sun;
//构造方法私有化
private Sun(){

}
//公有静态方法,返回实例对象
public static Sun getInstance() {
if (sun == null) {
//加锁排队进入
synchronized(Sun.class){
//如果类没有实例化对象,才实例化
sun = new Sun();
}
}
return sun;
}
}

总结

    大多数情况下,我会选择饿汉模式,因为这个单例迟早是要被实例化占用内存的,延迟懒加载省内存可以带来一定的好处,但是加锁解锁会降低CPU的利用率,也带来了一定坏处,二者对比起来,我更愿意选择代码简单的饿汉模式。


Python实现单例模式

python的单例模式有多种实现方法,思想是相同的:

  • 使用函数装饰器实现单例
  • 使用类装饰器实现单例
  • 使用 new 关键字实现单例
  • 使用 metaclass 实现单例

具体请参考:Python单例模式(Singleton)的N种实现