2013-05-10 3 views
1

Я пытаюсь найти свой собственный путь реализации Java Singleton. код выглядит следующим образом:Пример внедрения Singleton

public class Singleton{ 
    private volatile static Singleton _instance = null; 
    private Singleton(){} 
    public static Singleton getInstance(){ 
     if (_instance == null) 
     Object obj = new Object(); 
     synchronized(obj){ 
      if (_instance == null) 
       _instance = new Singleton(); 
     } 
     return _instance; 
} 

ли этот код работать? Если не работает, как его исправить?

+0

Вы используете локальную блокировку метода, которая полностью аннулирует вашу синхронизацию (фактически, ее нет). – Perception

+0

Вы должны взглянуть на реализацию синглтона Jon Skeet's. В значительной степени затрагивает вашу проблему. – christopher

+0

Вот еще один вопрос, показывающий метод Скита, упомянутый выше [http://stackoverflow.com/questions/2912281/thread-safety-in-singleton] – mconlin

ответ

0

Нет, это неправильно, вы должны синхронизировать данные на Singleton.class

class Singleton { 
     private volatile static Singleton _instance; 
     private Singleton(){} 
     public static Singleton getInstance(){ 
      if (_instance == null) 
      synchronized(Singleton.class){ 
       if (_instance == null) 
        _instance = new Singleton(); 
      } 
      return _instance; 
    } 
} 

это известный двойной проверкой блокировки шаблона см http://www.ibm.com/developerworks/java/library/j-dcl/index.html подробности

Обратите внимание, что, поскольку существует только один метод в этом классе следующие служит той же цели без каких-либо двойных проверены трюков и слишком ленив

class Singleton { 
     private static Singleton _instance = new Singleton(); 
     private Singleton(){} 
     public static Singleton getInstance(){ 
      return _instance; 
    } 
} 
+0

fyi дважды проверенная блокировка считается анти-шаблоном – Bohemian

+0

Я согласен, см. Обновление –

+1

нет необходимости в volatile во втором варианте. – assylias

1

было бы лучше, если ваш объект синхронизации - final static. В противном случае каждый возможный параллельный поток создаст свой собственный объект синхронизации и заблокирует разные объекты. И они не будут ждать друг друга.

public class Singleton{ 

    private final static Object obj = new Object(); 
    private volatile static Singleton _instance = null; 

    private Singleton(){} 

    public static Singleton getInstance(){ 
    if (_instance == null) 
     synchronized(obj){ 
      if (_instance == null) 
       _instance = new Singleton(); 
     } 
     } 
     return _instance; 
    } 
+0

Да. Я нахожу свою проблему. Объект не может быть в методе. В противном случае при каждом вызове метода создается новый другой объект. Не работает. – Zachary

2

Ticky и очень простая реализация не-ленивым одноточечного:

public enum TickySingleton { 

    INSTANCE; 

    public void doSomething() { ... } 
    public Object returnSomething() { ... } 
} 

}

Не все понравится. ;)

+0

Я только что узнал, что кто-то написал об этой реализации здесь: http://stackoverflow.com/questions/2912281/thread-safety-in-singleton – rebeliagamer

+1

Этот «шаблон однократной перезаписи» также рекомендуется Джошем Блохом в книге «Эффективная Java» ' – eiden

1

При записи:

Object obj = new Object(); 
synchronized(obj){} 

Виртуальная машина Java может доказать, что никакие два потока не может получить эту блокировку (потому что она является локальной переменной) и, следовательно, может полностью удалить синхронизацию.

Несколько замечаний о одиночках:

3

Нет - ваш код не работает, поскольку объект блокировки является локальной переменной и, следовательно, отличается для каждого потока.

Вы пытаетесь реализовать шаблон 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 экземпляра, даже думая, что он создан лениво. Также обратите внимание, насколько чистый и простой код.