Другими словами, предположим, что у нас есть два идеально гоночных потока:
- THREAD 1: "if instance! = Null" ... хорошо, это null.
- THREAD 2: "if instance! = Null" ... хорошо, это ноль.
- THREAD 1: создает новый "instance"
- THREAD 2: STOMPS ON значение, только что созданное потоком 1.
... и, вполне вероятно, ни один из потоков в настоящее время не знает, что что-то не так. Вполне вероятно, что они оба думают, что у них есть DoubleCheckSingleton
и используют их так, как они должны… ни один из них не осознает, что есть два. (Так что, откиньтесь на спинку кресла и смотрите данные - структуры рушатся влево и вправо, когда ваше приложение упало в землю.)
Еще хуже, это именно та ошибка, которая "случается однажды в синей луне". То есть, это никогда не происходит ни на одном компьютере разработчика, но это происходит через пять минут после развертывания в рабочей среде ... ; -)
Ключевое слово volatile
в основном говорит, что "это место хранения, само по себе является общим ресурсом." Что это такое.
Теперь также: я думаю, что наилучшей практикой является инициализация всех ваших объектов синхронизации до того, как вы начнете запускать потоки или подпроцессы. Все эти сущности теперь могут ссылаться на эти уже существующие объекты и могут использовать их, но никто из этих игроков никогда не создает их.