|
13 | 13 |
|
14 | 14 | namespace Singleton
|
15 | 15 | {
|
16 |
| - // EN: The Singleton class defines the `getInstance` method that lets |
17 |
| - // clients access the unique singleton instance. |
| 16 | + // EN: This Singleton implementation is called "double check lock". It is |
| 17 | + // safe in multithreaded environment and provides lazy initialization for |
| 18 | + // the Singleton object. |
18 | 19 | //
|
19 |
| - // RU: Класс Одиночка предоставляет метод getInstance, который позволяет |
20 |
| - // клиентам получить доступ к уникальному экземпляру одиночки. |
| 20 | + // RU: Эта реализация Одиночки называется "блокировка с двойной проверкой" |
| 21 | + // (double check lock). Она безопасна в многопоточной среде, а также |
| 22 | + // позволяет отложенную инициализацию объекта Одиночки. |
21 | 23 | class Singleton
|
22 | 24 | {
|
| 25 | + private Singleton() { } |
| 26 | + |
23 | 27 | private static Singleton _instance;
|
24 | 28 |
|
| 29 | + // EN: We now have a lock object that will be used to synchronize |
| 30 | + // threads during first access to the Singleton. |
| 31 | + // |
| 32 | + // RU: У нас теперь есть объект-блокировка для синхронизации потоков во |
| 33 | + // время первого доступа к Одиночке. |
25 | 34 | private static readonly object _lock = new object();
|
26 |
| - |
27 |
| - private string _value; |
28 | 35 |
|
29 |
| - public Singleton(string value) |
30 |
| - { |
31 |
| - this._value = value; |
32 |
| - } |
33 |
| - |
34 |
| - public string GetValue() |
35 |
| - { |
36 |
| - return this._value; |
37 |
| - } |
38 |
| - |
39 |
| - // EN: The static method that controls the access to the singleton |
40 |
| - // instance. |
41 |
| - // |
42 |
| - // This implementation let you subclass the Singleton class while |
43 |
| - // keeping just one instance of each subclass around. |
44 |
| - // |
45 |
| - // RU: Статический метод, управляющий доступом к экземпляру одиночки. |
46 |
| - // |
47 |
| - // Эта реализация позволяет вам расширять класс Одиночки, сохраняя |
48 |
| - // повсюду только один экземпляр каждого подкласса. |
49 | 36 | public static Singleton GetInstance(string value)
|
50 | 37 | {
|
51 |
| - lock (_lock) |
| 38 | + // EN: This conditional is needed to prevent threads stumbling over |
| 39 | + // the lock once the instance is ready. |
| 40 | + // |
| 41 | + // RU: Это условие нужно для того, чтобы не стопорить потоки |
| 42 | + // блокировкой после того как объект-одиночка уже создан. |
| 43 | + if (_instance == null) |
52 | 44 | {
|
53 |
| - if (_instance == null) |
| 45 | + // EN: Now, imagine that the program has just been launched. |
| 46 | + // Since there's no Singleton instance yet, multiple threads can |
| 47 | + // simultaneously pass the previous conditional and reach this |
| 48 | + // point almost at the same time. The first of them will acquire |
| 49 | + // lock and will proceed further, while the rest will wait here. |
| 50 | + // |
| 51 | + // RU: Теперь представьте, что программа была только-только |
| 52 | + // запущена. Объекта-одиночки ещё никто не создавал, поэтому |
| 53 | + // несколько потоков вполне могли одновременно пройти через |
| 54 | + // предыдущее условие и достигнуть блокировки. Самый быстрый |
| 55 | + // поток поставит блокировку и двинется внутрь секции, пока |
| 56 | + // другие будут здесь его ожидать. |
| 57 | + lock (_lock) |
54 | 58 | {
|
55 |
| - _instance = new Singleton(value); |
| 59 | + // EN: The first thread to acquire the lock, reaches this |
| 60 | + // conditional, goes inside and creates the Singleton |
| 61 | + // instance. Once it leaves the lock block, a thread that |
| 62 | + // might have been waiting for the lock release may then |
| 63 | + // enter this section. But since the Singleton field is |
| 64 | + // already initialized, the thread won't create a new |
| 65 | + // object. |
| 66 | + // |
| 67 | + // Первый поток достигает этого условия и проходит внутрь, |
| 68 | + // создавая объект-одиночку. Как только этот поток покинет |
| 69 | + // секцию и освободит блокировку, следующий поток может |
| 70 | + // снова установить блокировку и зайти внутрь. Однако теперь |
| 71 | + // экземпляр одиночки уже будет создан и поток не сможет |
| 72 | + // пройти через это условие, а значит новый объект не будет |
| 73 | + // создан. |
| 74 | + if (_instance == null) |
| 75 | + { |
| 76 | + _instance = new Singleton(); |
| 77 | + _instance.Value = value; |
| 78 | + } |
56 | 79 | }
|
57 | 80 | }
|
58 | 81 | return _instance;
|
59 | 82 | }
|
| 83 | + |
| 84 | + // EN: We'll use this property to prove that our Singleton really works. |
| 85 | + // |
| 86 | + // RU: Мы используем это поле, чтобы доказать, что наш Одиночка |
| 87 | + // действительно работает. |
| 88 | + public string Value { get; set; } |
60 | 89 | }
|
61 | 90 |
|
62 | 91 | class Program
|
@@ -93,7 +122,7 @@ static void Main(string[] args)
|
93 | 122 | public static void TestSingleton(string value)
|
94 | 123 | {
|
95 | 124 | Singleton singleton = Singleton.GetInstance(value);
|
96 |
| - Console.WriteLine(singleton.GetValue()); |
| 125 | + Console.WriteLine(singleton.Value); |
97 | 126 | }
|
98 | 127 | }
|
99 | 128 | }
|
0 commit comments