Update 设计模式 - 单例.md

小节标题改为中文,重新绘制类图,统一重排序的术语,补充参考资料。
This commit is contained in:
CyC2018
2026-10-28 03:19:54 +08:00
parent 49a17948f9
commit fda671d5a1
2 changed files with 13 additions and 14 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

+13 -14
View File
@@ -1,19 +1,16 @@
## 单例(Singleton)
### Intent
### 意图
确保一个类只有一个实例,并提供该实例的全局访问点。
### Class Diagram
### 类图
使用一个私有构造函数、一个私有静态变量以及一个公有静态函数来实现。
私有构造函数保证了不能通过构造函数来创建对象实例,只能通过公有静态函数返回唯一的私有静态变量。
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/eca1f422-8381-409b-ad04-98ef39ae38ba.png"/> </div><br>
### Implementation
<div align="center"> <img src="pics/dp-singleton.png" width="760px"/> </div><br>
### 实现
#### Ⅰ 懒汉式-线程不安全
以下实现中,私有静态变量 uniqueInstance 被延迟实例化,这样做的好处是,如果没有用到该类,那么就不会实例化 uniqueInstance,从而节约资源。
@@ -105,9 +102,9 @@ uniqueInstance 采用 volatile 关键字修饰也是很有必要的, `uniqueIn
2. 初始化 uniqueInstance
3. 将 uniqueInstance 指向分配的内存地址
但是由于 JVM 具有指令重排的特性,执行顺序有可能变成 1>3>2。指令重排在单线程环境下不会出现问题,但是在多线程环境下会导致一个线程获得还没有初始化的实例。例如,线程 T<sub>1</sub> 执行了 1 和 3,此时 T<sub>2</sub> 调用 getUniqueInstance() 后发现 uniqueInstance 不为空,因此返回 uniqueInstance,但此时 uniqueInstance 还未被初始化。
但是由于 JVM 具有重排序的特性,执行顺序有可能变成 1>3>2。重排序在单线程环境下不会出现问题,但是在多线程环境下会导致一个线程获得还没有初始化的实例。例如,线程 T<sub>1</sub> 执行了 1 和 3,此时 T<sub>2</sub> 调用 getUniqueInstance() 后发现 uniqueInstance 不为空,因此返回 uniqueInstance,但此时 uniqueInstance 还未被初始化。
使用 volatile 可以禁止 JVM 的指令重排,保证在多线程环境下也能正常运行。
使用 volatile 可以禁止 JVM 的重排序,保证在多线程环境下也能正常运行。
#### Ⅴ 静态内部类实现
@@ -175,7 +172,7 @@ public enum Singleton {
}
```
```html
```text
firstName
secondName
secondName
@@ -186,16 +183,18 @@ secondName
该实现在多次序列化和反序列化之后,不会得到多个实例。而其它实现需要使用 transient 修饰所有字段,并且提供 readResolve() 方法。
### Examples
### 示例
- Logger Classes
- Configuration Classes
- Accessing resources in shared mode
- Factories implemented as Singletons
### JDK
### JDK 中的应用
- [java.lang.Runtime#getRuntime()](http://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#getRuntime%28%29)
- [java.awt.Desktop#getDesktop()](http://docs.oracle.com/javase/8/docs/api/java/awt/Desktop.html#getDesktop--)
- [java.lang.System#getSecurityManager()](https://docs.oracle.com/javase/8/docs/api/java/lang/System.html#getSecurityManager--)
## 参考资料
- 弗里曼. Head First 设计模式 [M]. 中国电力出版社, 2007.
- Gamma E. 设计模式: 可复用面向对象软件的基础 [M]. 机械工业出版社, 2007.