Модераторы: LSD, AntonSaburov
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Синхронизация синглетона, на этапе создания 
:(
    Опции темы
UnicornMirage
Дата 26.5.2006, 10:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 138
Регистрация: 15.11.2005

Репутация: 1
Всего: 1



Добрый день всем участникам форума!

позвольте задать такой вопрос:
У меня есть класс построенный по шаблону Singleton. Экземпляр этого класса используется в мультипоточном контексте (сервлетами). Для создания экземпляра класса использую фабрику:

Код

class MySingleton {
        private static MySingleton oneInst;

        private  MySingleton () {} 

        /**
         * данный метод я синхронизирую чтобы изключить возможность множественных вызов
         * из разных потоков
         */
        public static synchronized  MySingleton getInstance () {
                if(oneInst == null) {
                        oneInst = new  MySingleton ();
                }
                return oneInst ;
        }
}


Так как экземпляр класса MySingleton используется очень часто,  разумеется мне не понравилось что при получении ссылки на него приходится вызывать синхронизированный метод getInstance. Тогда я сделал вторую фабрику:

Код

class MegaFactory {
        private static MySingleton oneInst;

       public static  MySingleton getMySingleton() {
              if (oneInst == null) {
                      oneInst = MySingleton.getInstance();  // синхронизация используется один раз
              }
              return  oneInst;
       }
}


у фабрики MegaFactory есть метод getMySingleton который не синхронизирован, тем не менее синхрнонизация используется внутри него при условии если объект класса MySingleton не создан.

Потом у меня возникла идея отказаться от этой фабрики и сделать таким образом:
Код

class MySingleton {
        private static MySingleton oneInst = new MySingleton ();

        private  MySingleton () {} 

        /**
         * данный метод уже не синхронизирован
         */
        public static MySingleton getInstance () {
                return oneInst ;
        }
}


Скажите пожалуйста, правильно ли я сдеал? Какой из этих вариантов лучший? Или синхронизация не нужна вообще в этой задаче?
Спасибо за внимание!  

Это сообщение отредактировал(а) UnicornMirage - 26.5.2006, 10:02
PM MAIL   Вверх
chief39
Дата 26.5.2006, 10:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


карманная тигра
***


Профиль
Группа: Участник Клуба
Сообщений: 1631
Регистрация: 20.5.2005
Где: Киев

Репутация: 15
Всего: 77



Проверка на null и создание должны быть в одном синхронайзе. Выносить проверку как во втором случае нет смысла - зачем тогда синхронайз вообще?
Ибо получится так:
   Первый поток проверяет - налл!!! 
    Второй поток проверяет - налл!!!
   первый поток делает new
   второй поток (условие он-то раньше проверил) тоже делает new

Сделай первый вариант, с синхронайзом внутри, чтоб меньше времени занимал(лочил) ресурс.

Код

 public static MySingleton getInstance () {
                synchronized(this){  
                    if(oneInst == null) {
                            oneInst = new  MySingleton ();
                    }
                }
                return oneInst ;
    
    }  

Это сообщение отредактировал(а) chief39 - 26.5.2006, 10:14


--------------------
Люди - это свечи. Они либо горят, либо их - в жопу!(с)

PM MAIL   Вверх
UnicornMirage
Дата 26.5.2006, 10:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 138
Регистрация: 15.11.2005

Репутация: 1
Всего: 1



Цитата

Проверка на null и создание должны быть в одном синхронайзе.


я конечно может не понял глубину проблемы - но ведь у меня как раз есть в коде единственный синхронизированный блок в котором идет проверка на null и создание экземпляра. 
как я полагал, если несколько потоков одновременно попали в метод MegaFactory.getMySingleton(); то только один поток сможет выполнить метод MySingleton.getInstance();

что касается приведенного Вами примера кода - разве он не будет медленнее? (если я не ошибаюсь, на вашем форуме где то обсуждалась проблема что быстрее - вынести синхронизацию в метод либо использовать внутри)... 
PM MAIL   Вверх
allex
Дата 26.5.2006, 10:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 59
Регистрация: 5.9.2005

Репутация: нет
Всего: нет



Вы что, сговорились все вокруг про синхронизацию синглетонов говорить? smile
http://jroller.com/page/sana167?entry=sync...n_in_singletons
Там в обсуждении есть полезные ссылки. 
PM MAIL   Вверх
chief39
Дата 26.5.2006, 11:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


карманная тигра
***


Профиль
Группа: Участник Клуба
Сообщений: 1631
Регистрация: 20.5.2005
Где: Киев

Репутация: 15
Всего: 77



Цитата(UnicornMirage @  26.5.2006,  10:21 Найти цитируемый пост)
но ведь у меня как раз есть в коде единственный синхронизированный блок в котором идет проверка на null и создание экземпляра. 

Во втором примере проверка на налл ВНЕ СИНХРОНАЙЗА


Цитата(UnicornMirage @  26.5.2006,  10:21 Найти цитируемый пост)
если несколько потоков одновременно попали в метод MegaFactory.getMySingleton(); то только один поток сможет выполнить метод MySingleton.getInstance();

Ага. А второй (тоже уверившийся ранее, что пока ещё имеем налл) подождёт, а потом тоже его выполнит.


Цитата(UnicornMirage @  26.5.2006,  10:21 Найти цитируемый пост)
разве он не будет медленнее? (если я не ошибаюсь, на вашем форуме где то обсуждалась проблема что быстрее - вынести синхронизацию в метод либо использовать внутри)...  


Синхронизировать сам метод будет медленнее, чем кусок кода внутри метода.
Наименее возможный.
Наименее возможный в нашем варианте - это проверка + создание.
Вот мы их и синхронизнули smile Больше ничего  


--------------------
Люди - это свечи. Они либо горят, либо их - в жопу!(с)

PM MAIL   Вверх
UnicornMirage
Дата 26.5.2006, 12:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 138
Регистрация: 15.11.2005

Репутация: 1
Всего: 1



Цитата(allex @ 26.5.2006,  10:36)
Вы что, сговорились все вокруг про синхронизацию синглетонов говорить? smile
http://jroller.com/page/sana167?entry=sync...n_in_singletons
Там в обсуждении есть полезные ссылки.

большое спасибо за ссылку!
там есть интересная статья - Double-checked locking and the Singleton pattern

в частности как я понял из нее там говорится:
Цитата

...
Listing 10. Singleton implementation with static field
Код

class Singleton
{
  private Vector v;
  private boolean inUse;
  private static Singleton instance = new Singleton();

  private Singleton()
  {
    v = new Vector();
    inUse = true;
    //...
  }

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

The code in Listing 10 does not use synchronization and ensures that the Singleton object is not created until a call is made to the static getInstance() method. This is a good alternative if your objective is to eliminate synchronization.


значит достаточно этого подхода чтобы гарантировать корректное создание экземпляра синглетона в мультипоточном контексте? 
PM MAIL   Вверх
UnicornMirage
Дата 26.5.2006, 12:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 138
Регистрация: 15.11.2005

Репутация: 1
Всего: 1



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

Исходный синглетон:
Код

public class MySingleton {
    private static MySingleton s = new MySingleton();

    private MySingleton() {
        System.out.println("invoke MySingleton()");
    }

    public static MySingleton getInstance() {
        return s;
    }
}


Небольшой тест:
Код

public class TestSyncSingleton {
    public static void main(String[] args) {
        System.out.println(0);
        MySingleton a;
        
        System.out.println(1);
        MySingleton.class.getClass();
        
        System.out.println(2);
        MySingleton s = MySingleton.getInstance();
    }
}



вот что выводится в консоль:
Код

0
1
2
invoke MySingleton()


Удивительно! раньше я думал (и не додумался проверять) что статическая инициализация в любом классе происходит при любом первом обращении к классу. Оказывается там завязано все на ссылки? Тоесть на шаге 2 метод MySingleton.getInstance(); работает со ссылкой, и поэтому она инициилизируется..

теперь осталось протестировать в многопоточной среде. только вот как написать корректный тест - еще следует подумать. 
PM MAIL   Вверх
Beard
Дата 26.5.2006, 13:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 228
Регистрация: 5.7.2005
Где: Санкт-Петербург

Репутация: 2
Всего: 9



   
to Chief39: 
Цитата

Код

public static MySingleton getInstance () {
                synchronized(this){  
...


А ничего, что метод статик - this-то не доступна!? smile
Да и synchronize будет выполняться всегда - лучше уж лишнюю проверку:
Код

public class MySingleton {
    private static MySingleton _self$;
    private static Object _lock = new Object();

    private MySingleton() {
        // ...
    }

    public static MySingleton getInstance() {
        if (_self$ != null)
            return _self$;
        else {
            synchronized (_lock)/*or by class*/ {
                if (_self$ == null)
                    _self$ = new MySingleton();
                return _self$;
            }
        }
    }
}

     
PM MAIL   Вверх
chief39
Дата 26.5.2006, 14:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


карманная тигра
***


Профиль
Группа: Участник Клуба
Сообщений: 1631
Регистрация: 20.5.2005
Где: Киев

Репутация: 15
Всего: 77



Цитата(Beard @  26.5.2006,  13:22 Найти цитируемый пост)
А ничего, что метод статик - this-то не доступна!?

Тупанул smile)) Безоговорочно smile))

С правкой согласен (подпись smile)

Цитата(UnicornMirage @  26.5.2006,  12:19 Найти цитируемый пост)
Удивительно! раньше я думал (и не додумался проверять) что статическая инициализация в любом классе происходит при любом первом обращении к классу. Оказывается там завязано все на ссылки? Тоесть на шаге 2 метод MySingleton.getInstance(); работает со ссылкой, и поэтому она инициилизируется..


Статик инициализируется при первом же её затрагивании.
Вот только прикол в с наследованием - если статики есть в родителе и в сыне, то при затрагивании статика сына - инитнутся все статики сына, но не отца(!!!).
А если дёрнуть какой-либо статик отца - тогда и его все статики доинитятся.
Где-то была тема - раскапывали по кусочкам smile

В общем-то решение правильное откопал smile

Одно НО - если кто-то(из самой фактори то есть smile ) изменит сию статик ссылку - тогда следующий гетинстанс получит null, так как создавать сам не умеет.
лучше уж добавить туда final модификатор  

Это сообщение отредактировал(а) chief39 - 26.5.2006, 14:32


--------------------
Люди - это свечи. Они либо горят, либо их - в жопу!(с)

PM MAIL   Вверх
Beard
Дата 26.5.2006, 14:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 228
Регистрация: 5.7.2005
Где: Санкт-Петербург

Репутация: 2
Всего: 9



Цитата

Одно НО - если кто-то изменит сию статик ссылку - тогда следующий гетинстанс получит null, так как создавать сам не умеет.

Не совсем понял - кто может изменить, кроме самого singleton-a?  
PM MAIL   Вверх
chief39
Дата 26.5.2006, 15:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


карманная тигра
***


Профиль
Группа: Участник Клуба
Сообщений: 1631
Регистрация: 20.5.2005
Где: Киев

Репутация: 15
Всего: 77



Цитата(Beard @  26.5.2006,  14:44 Найти цитируемый пост)
Не совсем понял - кто может изменить, кроме самого singleton-a?   

Я дописал в скобочках(пардон только что факторией обозвал - на автомате)smile

Вот он сам и может. А ежели методов у него много - то в одном из них и может произойти бяка. (мало ли кто его будет дописывать). Но final тут не повредит.
 


--------------------
Люди - это свечи. Они либо горят, либо их - в жопу!(с)

PM MAIL   Вверх
allex
Дата 26.5.2006, 15:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 59
Регистрация: 5.9.2005

Репутация: нет
Всего: нет



UnicornMirage, а между прочим, условия инициализации класса подробно описаны в JLS.

12.4.1 When Initialization Occurs
Initialization of a class consists of executing its static initializers and the initializers for static fields declared in the class. Initialization of an interface consists of executing the initializers for fields declared in the interface.
Before a class is initialized, its direct superclass must be initialized, but interfaces implemented by the class need not be initialized. Similarly, the superinterfaces of an interface need not be initialized before the interface is initialized. 

A class or interface type T will be initialized immediately before the first occurrence of any one of the following: 
  • T is a class and an instance of T is created. 
  • T is a class and a static method declared by T is invoked. 
  • A static field declared by T is assigned. 
  • A static field declared by T is used and the field is not a constant variable (§4.12.4). 
  • T is a top-level class, and an assert statement (§14.10) lexically nested within T is executed.
Invocation of certain reflective methods in class Class and in package java.lang.reflect also causes class or interface initialization. A class or interface will not be initialized under any other circumstance.
 
PM MAIL   Вверх
Beard
Дата 26.5.2006, 15:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 228
Регистрация: 5.7.2005
Где: Санкт-Петербург

Репутация: 2
Всего: 9



Цитата

Вот он сам и может. А ежели методов у него много - то в одном из них и может произойти бяка. (мало ли кто его будет дописывать). 

да, не повезет конторе, если она возьмет такого программера, что instance напрямую будет юзать в других методах smile
Цитата

Но final тут не повредит

согласен 
PM MAIL   Вверх
chief39
Дата 26.5.2006, 16:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


карманная тигра
***


Профиль
Группа: Участник Клуба
Сообщений: 1631
Регистрация: 20.5.2005
Где: Киев

Репутация: 15
Всего: 77



Цитата(Beard @  26.5.2006,  15:56 Найти цитируемый пост)
да, не повезет конторе, если она возьмет такого программера, что instance напрямую будет юзать в других методах

Ммм.... "никогда не говори никогда" smile Мало ли что бывает в этом мире ;)
А уж если возьмут такого программера - то final не даст "не повезти" smile

Это  не к тому, что его нужно дёргать - но к тому, что если он у нас не должен изменяться по логике - тогда мы ему и запрещаем это делать.
По аналогии с дядькой Эккелем: "если можем сделать не абстрактный класс, а интерфейс - делайте, обратно всегда успеется". smile

Расфилософствовались... smile 


--------------------
Люди - это свечи. Они либо горят, либо их - в жопу!(с)

PM MAIL   Вверх
UnicornMirage
Дата 27.5.2006, 17:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 138
Регистрация: 15.11.2005

Репутация: 1
Всего: 1



Всем большое спасибо за обсуждение, из которого удалось почерпнуть много хороших идей и ссылок!
Если бы мог, то бы поставил всем + надеюсь за меня это сделает кто нибудь.. smile 
   

Это сообщение отредактировал(а) UnicornMirage - 27.5.2006, 17:38
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
javastic
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux, javastic.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0635 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.