Я не думаю, что кто-то действительно ответил на вопрос , поэтому я попробую.
Летучие и первые if (instance == null)
не «нужны». Блокировка сделает этот код потокобезопасным.
Возникает вопрос: зачем добавлять первое if (instance == null)
?
Причина, по-видимому, в том, чтобы избежать ненужного выполнения заблокированной части кода. Пока вы выполняете код внутри блокировки, любой другой поток, который пытается также выполнить этот код, блокируется, что замедлит вашу программу, если вы попытаетесь часто получить доступ к синглтону из многих потоков. В зависимости от языка / платформы могут возникнуть накладные расходы из-за самой блокировки, которых вы хотите избежать.
Таким образом, первая нулевая проверка добавляется как действительно быстрый способ узнать, нужна ли вам блокировка. Если вам не нужно создавать синглтон, вы можете полностью избежать блокировки.
Но вы не можете проверить, является ли ссылка нулевой, не заблокировав ее каким-либо образом, потому что из-за кэширования процессора другой поток может ее изменить, и вы прочитаете «устаревшее» значение, которое приведет к ненужному вводу блокировки. Но вы пытаетесь избежать блокировки!
Таким образом, вы делаете синглтон изменчивым, чтобы гарантировать, что вы читаете последнее значение, без необходимости использовать блокировку.
Вам по-прежнему нужна внутренняя блокировка, потому что volatile защищает вас только во время однократного доступа к переменной - вы не можете безопасно проверить и установить ее без использования блокировки.
Так вот, действительно ли это полезно?
Я бы сказал «в большинстве случаев нет».
Если Singleton.Instance может вызвать неэффективность из-за блокировок, то почему вы вызываете его так часто, что это может стать серьезной проблемой ? Весь смысл синглтона в том, что он только один, поэтому ваш код может прочитать и кэшировать ссылку на синглтон один раз.
Единственный случай, когда я могу думать о том, где это кеширование было бы невозможно, - это когда у вас есть большое количество потоков (например, сервер, использующий новый поток для обработки каждого запроса, может создавать миллионы очень коротких потоков, каждый из которых который должен был бы вызвать Singleton.Instance один раз).
Поэтому я подозреваю, что блокировка с двойной проверкой - это механизм, который имеет реальное место в очень специфических случаях, критичных к производительности, и затем все забрались на «это правильный способ сделать это», не задумываясь, что он делает и действительно ли будет действительно необходимо в случае, если они его используют.