|
| 1 | +import threading |
| 2 | + |
| 3 | + |
1 | 4 | class SingletonMeta(type):
|
2 | 5 | """
|
3 |
| - The Singleton class can be implemented in different ways in Python. Some |
4 |
| - possible methods include: base class, decorator, metaclass. We will use the |
5 |
| - metaclass because it is best suited for this purpose. |
| 6 | + Thread-safe Singleton Meta with double-checked locking. |
| 7 | + Reference: https://en.wikipedia.org/wiki/Double-checked_locking |
6 | 8 | """
|
7 | 9 |
|
8 | 10 | _instances = {}
|
| 11 | + _lock = threading.Lock() |
9 | 12 |
|
10 | 13 | def __call__(cls, *args, **kwargs):
|
11 |
| - """ |
12 |
| - Possible changes to the value of the `__init__` argument do not affect |
13 |
| - the returned instance. |
14 |
| - """ |
| 14 | + # First check (without locking) for performance reasons |
15 | 15 | if cls not in cls._instances:
|
16 |
| - instance = super().__call__(*args, **kwargs) |
17 |
| - cls._instances[cls] = instance |
| 16 | + # Acquire a lock before proceeding to the second check |
| 17 | + with cls._lock: |
| 18 | + # Second check with lock held to ensure thread safety |
| 19 | + if cls not in cls._instances: |
| 20 | + instance = super().__call__(*args, **kwargs) |
| 21 | + cls._instances[cls] = instance |
18 | 22 | else:
|
19 | 23 | assert (
|
20 | 24 | len(args) == 0 and len(kwargs) == 0
|
21 |
| - ), f"{cls.__name__} is a singleton class and a instance has been created." |
| 25 | + ), f"{cls.__name__} is a singleton class and an instance has been created." |
| 26 | + |
22 | 27 | return cls._instances[cls]
|
0 commit comments