Нет - ваш код не работает, поскольку объект блокировки является локальной переменной и, следовательно, отличается для каждого потока.
Вы пытаетесь реализовать шаблон lazy initialization - где экземпляр создается при первом использовании.
Но есть простой трюк, который позволяет вам закодировать поточно-безопасную реализацию, которую не требует синхронизации!Он известен как Initialization-on-demand holder idiom, и это выглядит следующим образом:
public class Singleton {
private static class Holder {
static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return Holder.INSTANCE;
}
private Singleton() {
}
// rest of class omitted
}
Этот код инициализирует экземпляр на первом призвании getInstance()
, а главное dosen't синхронизации необходимо из-за договора загрузчиком класса:
- классов загрузчик классов нагрузок при их первом обращении (в данном случае
Holder
«ы только доступа находится в пределах GetInstance()` метод)
- когда загружается класс, и, прежде чем кто-либо может использовать его, все статические инициализаторы гарантированно выполняются (это wh ан
Holder
«s статический блок пожаров)
- загрузчик классов имеет свою собственную синхронизацию встроен прямо в том, что делают вышеуказанные два пункта гарантированно потокобезопасны
Это аккуратный маленький трюк, который я использую, когда мне нужно ленивой инициализации , Вы также получаете бонус final
экземпляра, даже думая, что он создан лениво. Также обратите внимание, насколько чистый и простой код.
Вы используете локальную блокировку метода, которая полностью аннулирует вашу синхронизацию (фактически, ее нет). – Perception
Вы должны взглянуть на реализацию синглтона Jon Skeet's. В значительной степени затрагивает вашу проблему. – christopher
Вот еще один вопрос, показывающий метод Скита, упомянутый выше [http://stackoverflow.com/questions/2912281/thread-safety-in-singleton] – mconlin