2010-03-26 5 views
6
public static MySingleton getInstance() { 
if (_instance==null) { 
    synchronized (MySingleton.class) { 
     _instance = new MySingleton(); 
    } 
} 
return _instance; 
} 

1. Есть ли недостаток с вышеупомянутой реализацией метода getInstance? 2. В чем разница между двумя реализациями?singleton рисунок в java. ленивая инициализация

public static synchronized MySingleton getInstance() { 
if (_instance==null) { 
    _instance = new MySingleton(); 
} 

return _instance; 
} 

Я видел много ответов на одноплодной шаблон в StackOverflow, но вопрос, который я отправил, чтобы знать, в основном разница «Синхронизировать» в методе и блочном уровне в данном конкретном случае.

+0

http://stackoverflow.com/questions/70689/efficient-way-to-implement-singleton-pattern-in-java – skaffman

+0

Там в intrincate проблема с изменение вашего первого кода (вариант, который дважды проверяет недействительность, сначала за пределами синхронизированной и следующей внутри синхронизации). Это связано с тем, как компилятор и JVM делают что-то. Если вы ОЧЕНЬ заинтересованы, вы можете найти «двойную проверку инициализации java-проблемы». – helios

+0

Вам может быть интересна эта знаменитая статья о «проверенной двойной блокировкой», которая в основном приходит к выводу, что она сломана: http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf –

ответ

27

1. Есть ли недостаток с вышеуказанной реализацией метода getInstance ?

Не работает. Вы можете получить несколько экземпляров вашего Синглтона.

2.Что такое разница между двумя реализациями.?

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

Самый простой Правильная реализация:

public class MySingleton{ 
    private static final MySingleton _instance = new MySingleton(); 
    private MySingleton(){} 
    public static MySingleton getInstance() { 
     return _instance; 
    } 
} 

короче и лучше (безопасно сериализации):

public enum MySingleton{ 
    INSTANCE; 

    // methods go here 
} 

Ленивый инициализация одиночек это тема, которая получает внимание способ из пропорции с его фактическая практическая полезность (ИМО, спорящий о тонкостях двойной проверки блокировки, к которой ваш пример является первым шагом, представляет собой не что иное, как мошенничество).

В 99% всех случаев вам вообще не нужна ленивая инициализация, или «init когда класс в первую очередь относится» к Java достаточно хорош. В оставшемся 1% случаях, это является лучшим решением:

public enum MySingleton{ 
    private MySingleton(){} 
    private static class Holder { 
     static final MySingleton instance = new MySingleton(); 
    } 
    static MySingleton getInstance() { return Holder.instance; } 
} 
+1

перечисления не лениво инициализированы, хотя – skaffman

+0

Хорошие очки Майкл. Мне нравится ваша простая реализация. – Adrian

+0

@Tadeusz: спасибо, исправлено –

5

1. Есть ли недостаток с вышеуказанной реализацией метода getInstance ?

Да, синхронизированное ключевое слово должно также обернуть оператор if. Если это не так, то два или более потоков могут потенциально проникнуть в код создания.

2.Что такое разница между двумя реализациями?

Вторая реализация правильная и с моей точки зрения легче понять.

Использование синхронизации на уровне метода для статического метода синхронизируется с классом, то есть то, что вы сделали в примере 1. Использование синхронизации на уровне метода для метода экземпляра синхронизирует экземпляр объекта.

+0

@OP: В этой области вы найдете что-то, называемое «дважды проверенным шаблоном блокировки». Здесь вы проверяете, находите нуль, затем синхронизируете, затем проверяете снова (в случае, если что-то изменилось за это время), затем создайте. Он работает на многих языках, но * не работает в Java *, если вы не используете поле volatile для экземпляра, что означает «путь сверху». Лучше всего выполнить вторую реализацию, особенно с недавними JVM, которые очень эффективно обрабатывают синхронизированные блоки. Подробнее читайте здесь: http://www.ibm.com/developerworks/library/j-jtp02244.html –

+0

@OP мой комментарий выше, я должен был быть более понятным: он работает во многих * средах *, но не в JVM (если вы не используете поле volatile или его эквивалент - если есть - на используемом вами языке). Уточнение, потому что в наши дни Java - это всего лишь один из многих языков, который скомпилирован с использованием байт-кода Java и работает на JVM (и, аналогично, хотя и реже), есть некоторые компиляторы Java, которые компилируются в машинный код и не используют JVM). –

2

Второго один является поточно, но он имеет накладные расходы синхронизируются при каждом вызове, независимо от того, если экземпляр строится или нет.Первый вариант имеет один главный недостаток: у него нет проверки на наличие (_instance == null) в синхронизированном блоке, чтобы предотвратить создание двух экземпляров.

4

Первый дефект двумя способами. Как и другие упомянутые здесь, несколько потоков могут получить через

if (_instance==null) { 

Они ждут друг друга, пока объект не будет полностью построен, но они будут делать инстанцирование и заменить ссылку на переменную.

Второй недостаток немного сложнее. Один поток может попасть в конструктор new MySingleton(), а затем JVM переключается на другой поток. Другой поток может проверить переменную для null, но может содержать ссылку на частично построенный объект. Так что другая нить работает над частично построенным Синглтоном, это тоже не хорошо. Поэтому следует избегать первого варианта.

Второй вариант должен работать нормально. Не беспокойтесь о эффективности, пока вы не определите это как блокирующий. Современные JVM могут оптимизировать ненужные синхронизации, поэтому в реальном производственном коде эта конструкция никогда не повредит производительности.

4

Различные подходы к ленивой нагрузке синглетонам обсуждаются Боб Ли в Lazy Loading Singletons и «правильный» подход является Initialization on Demand Holder (IODH) idiom, который требует очень мало коды и имеет нулевую накладные расходов синхронизации.

static class SingletonHolder { 
    static Singleton instance = new Singleton();  
} 

public static Singleton getInstance() { 
    return SingletonHolder.instance; 
} 

Боб Ли также объясняет, когда он хочет ленить нагрузку на одноэлемент (во время испытаний и разработки). Честно говоря, я не уверен, что есть огромная выгода.

0

Я хотел бы предложить следующую реализацию

public class MySingleTon 
{ 

    private static MySingleton obj; 

    //private Constructor 
    private MySingleTon() 
    { 
    } 


    public static MySingleTon getInstance() 
    { 
    if(obj==null) 
    { 
     synchronized(MySingleTon.class) 
     { 
     if(obj == null) 
     { 
      obj = new MySingleTon(); 
     } 
     } 
    } 
    return obj;  
    } 
} 
+0

Это еще проверенная блокировка и поэтому по-прежнему неверна. –

Смежные вопросы