Поскольку статические переменные широко используются, они чрезвычайно безопасны для потоков.
Подумайте, что произойдет, если два потока вызывают ваш getInstance одновременно.Оба потока будут смотреть на общую статическую obj
, и оба потока увидят, что obj
пуст в проверке if.Затем оба потока создадут новое obj
.
. Вы можете подумать: «эй, это потокобезопасно, поскольку у obj будет только одно значение, даже если оно инициализируется несколько раз».Есть несколько проблем с этим утверждением.В нашем предыдущем примере вызывающие getInstance оба получат свои obj
обратно.Если оба абонента сохранят свои ссылки на obj
, то у вас будет несколько экземпляров используемого синглтона.
Даже если вызывающие абоненты в нашем предыдущем примере просто сделали: MyClass.getInstance();
и не сохранили ссылку начто вернуло MyClass.getInstance();
, вы все равно можете получить разные экземпляры из getInstance в этих потоках.Вы даже можете попасть в состояние, при котором новые экземпляры obj
создаются, даже когда вызовы getInstance не происходят одновременно!
Я знаю, что мое последнее утверждение кажется нелогичным, так как последнее назначение obj
Казалось бы, единственное значение, которое может быть возвращено из будущих вызовов на MyClass.getInstance()
.Однако вы должны помнить, что каждый поток в JVM имеет свой собственный локальный кэш основной памяти.Если два потока вызывают getInstance, их локальные кэши могут иметь разные значения, назначенные obj
, и будущие вызовы getInstance из этих потоков будут возвращать то, что находится в их кэшах.
Самый простой способ убедиться, что поток getInstance безопасенбыло бы сделать метод синхронизированным.Это гарантирует, что
- Два потока не могут одновременно войти в getInstance
- Потоки, пытающиеся использовать
obj
, никогда не получат устаревшее значение obj
из своего кэша
Не Не пытайтесь стать умным и используйте двойную проверку блокировки: http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html