|
3 | 3 | # 简介
|
4 | 4 | 单例模式(Singleton Pattern)属于创建型设计模式,这种模式只创建一个单一的类,保证一个类只有一个实例,并提供一个访问该实例的全局节点。
|
5 | 5 |
|
6 |
| -当您想控制实例数目,节省系统资源,并不想混用的时候,可以使用单例模式。 |
| 6 | +当您想控制实例数目,节省系统资源,并不想混用的时候,可以使用单例模式。单例有很多种实现方式,主要分为懒汉和饿汉模式,同时要通过加锁来避免线程安全。不同语言的单例实现略有差异,可以通过查看不同版本的源码来深入理解其中的差异。 |
7 | 7 |
|
8 | 8 | # 作用
|
9 | 9 | 1. 避免全局使用的类频繁地创建与销毁。
|
|
16 | 16 | # UML
|
17 | 17 | <img src="../docs/uml/singleton-pattern.png">
|
18 | 18 |
|
19 |
| -# 代码 |
| 19 | +# Java代码 |
20 | 20 |
|
21 | 21 | 单例实现,不同语言有很大不同,跟语言特性有关。请查看其他源码进行比较。
|
22 | 22 |
|
@@ -171,5 +171,147 @@ public class SingletonDoubleCheck {
|
171 | 171 | singletonInner1.run();
|
172 | 172 | singletonInner2.run();
|
173 | 173 | ```
|
| 174 | + |
| 175 | +# Go代码 |
| 176 | +```go |
| 177 | +// DoubleCheckSingleton.go |
| 178 | +import ( |
| 179 | + "fmt" |
| 180 | + "sync" |
| 181 | +) |
| 182 | + |
| 183 | +// 安全懒汉模式的升级版,通过sync的Mutex实现双重检验 |
| 184 | +type DoubleCheckSingleton struct { |
| 185 | + name string |
| 186 | +} |
| 187 | + |
| 188 | +func (s *DoubleCheckSingleton) Run() { |
| 189 | + fmt.Println("DoubleCheckSingleton::run()", s.name) |
| 190 | +} |
| 191 | + |
| 192 | +// 定义私有变量,用来保存实例 |
| 193 | +var doubleCheckSingletonInstance *DoubleCheckSingleton |
| 194 | +var lock = &sync.Mutex{} |
| 195 | + |
| 196 | +// 是懒汉模式安升级版,双重检查来来支持延迟实例化单例对象 |
| 197 | +func GetDoubleCheckSingletonInstance(name string) *DoubleCheckSingleton { |
| 198 | + // 未实例化才进行加锁 |
| 199 | + if doubleCheckSingletonInstance == nil { |
| 200 | + lock.Lock() |
| 201 | + defer lock.Unlock() |
| 202 | + // 为了保险,锁住之后再次检查是否已实例化 |
| 203 | + if doubleCheckSingletonInstance == nil { |
| 204 | + doubleCheckSingletonInstance = &DoubleCheckSingleton{} |
| 205 | + doubleCheckSingletonInstance.name = name |
| 206 | + } |
| 207 | + } |
| 208 | + |
| 209 | + return doubleCheckSingletonInstance |
| 210 | +} |
| 211 | + |
| 212 | +``` |
| 213 | + |
| 214 | +# JS版本 |
| 215 | +```js |
| 216 | +// LazySingleton.js |
| 217 | +export class LazySingleton { |
| 218 | + static instance |
| 219 | + constructor(alias) { |
| 220 | + this.alias = alias |
| 221 | + } |
| 222 | + |
| 223 | + // 懒汉模式,延迟实例化,请求实例时判断,如果已经实例化过就直接返回 |
| 224 | + // js是单线程语言,无需考虑多线程问题 |
| 225 | + static getInstance(alias) { |
| 226 | + if (this.instance === undefined) { |
| 227 | + this.instance = new LazySingleton(alias) |
| 228 | + } |
| 229 | + return this.instance |
| 230 | + } |
| 231 | + |
| 232 | + run() { |
| 233 | + console.log('LazySingleton::run()', this.alias) |
| 234 | + } |
| 235 | +} |
| 236 | +``` |
| 237 | + |
| 238 | +# Python语言 |
| 239 | +```py |
| 240 | +# SingletonSafe.py |
| 241 | +from threading import Lock, Thread |
| 242 | + |
| 243 | + |
| 244 | +# 加锁的基于元类的单例模式,基于元类type创建的加强版 |
| 245 | +class SingletonMeta(type): |
| 246 | + # 线程安全单例模式,适用python3 |
| 247 | + _instances = {} |
| 248 | + |
| 249 | + _lock: Lock = Lock() |
| 250 | + |
| 251 | + def __call__(cls, *args, **kwargs): |
| 252 | + with cls._lock: |
| 253 | + if cls not in cls._instances: |
| 254 | + instance = super().__call__(*args, **kwargs) |
| 255 | + cls._instances[cls] = instance |
| 256 | + return cls._instances[cls] |
| 257 | + |
| 258 | +# 继承SingletonMeta就是单例 |
| 259 | +class SingletonSafe(metaclass=SingletonMeta): |
| 260 | + name: str = None |
| 261 | + |
| 262 | + def __init__(self, name: str) -> None: |
| 263 | + self.name = name |
| 264 | + |
| 265 | + def run(self): |
| 266 | + print('SingletonSafe::run()', self.name) |
| 267 | + |
| 268 | +``` |
| 269 | + |
| 270 | +# C语言 |
| 271 | +```c |
| 272 | +// lazy_singleton_safe.c |
| 273 | +#include "func.h" |
| 274 | +#include <pthread.h> |
| 275 | + |
| 276 | +// 静态指针,未被创建并分配内存空间,指向唯一实例 |
| 277 | +static LazySingletonSafe *lazy_singleton_safe_instance = NULL; |
| 278 | + |
| 279 | +void lazy_singleton_safe_run(LazySingletonSafe *singleton) |
| 280 | +{ |
| 281 | + printf("\r\n LazySingletonSafe::run() [name=%s value=%d]", singleton->name, singleton->value); |
| 282 | +} |
| 283 | + |
| 284 | +// 内部私有实例化函数,不公开 |
| 285 | +static LazySingletonSafe *new_lazy_singleton_safe(char *name) |
| 286 | +{ |
| 287 | + LazySingletonSafe *singleton = (LazySingletonSafe *)malloc(sizeof(LazySingletonSafe)); |
| 288 | + strcpy(singleton->name, name); |
| 289 | + singleton->run = &lazy_singleton_safe_run; |
| 290 | + return singleton; |
| 291 | +} |
| 292 | + |
| 293 | +// 声明锁 |
| 294 | +pthread_mutex_t singleton_lock; |
| 295 | + |
| 296 | +// 非线程安全懒汉模式,延迟初始化。多个线程同时调用函数时, 可能会被初始化多次,存在线程不安全问题 |
| 297 | +LazySingletonSafe *get_lazy_singleton_safe_instance(char *name) |
| 298 | +{ |
| 299 | + printf("\r\n get_lazy_singleton_safe_instance() [name=%s]", name); |
| 300 | + if (pthread_mutex_init(&singleton_lock, NULL) != 0) |
| 301 | + { |
| 302 | + perror("error init mutext:"); |
| 303 | + } |
| 304 | + |
| 305 | + // 通过加锁来防止线程并发导致的不安全 |
| 306 | + if (lazy_singleton_safe_instance == NULL) |
| 307 | + { |
| 308 | + printf("\r\n new instance [name=%s]", name); |
| 309 | + pthread_mutex_lock(&singleton_lock); |
| 310 | + lazy_singleton_safe_instance = new_lazy_singleton_safe(name); |
| 311 | + pthread_mutex_unlock(&singleton_lock); |
| 312 | + } |
| 313 | + return lazy_singleton_safe_instance; |
| 314 | +} |
| 315 | +``` |
174 | 316 | ## 更多语言版本
|
175 | 317 | 不同语言实现设计模式:[https://github.com/microwind/design-pattern](https://github.com/microwind/design-pattern)
|
0 commit comments