Чекор по чекор
Почетни чекори со Java
Објектно оријентирани концепти во Јава - Прв дел
Објектно оријентирани концепти во Јава - Втор дел
Објектно оријентирани концепти во Јава - Трет дел
Јава сервлети - Прв дел
Единствен Јава објект (singleton)
Најчести 10 грешки што ги прават Java програмерите
повеќе...
Што е тоа ...
... IDE
... Tomcat
... објект?
... класа?
... наследување?
... интерфејс?
... наследување? (прашања и одговори)
повеќе...
За загревање
Нов проект во Eclipse?
Примитивни податочни типови
Променливи
Оператори
Доделувачки, аритметички и Unary оператори
Оператори за еднаквост, релации и услови
Изрази, искази и блокови
повеќе...
Како да ...
... конвертирам java.sql.Timestamp во java.util.Date
... зададам формат на датум
... ковертирам „long“ во HEX и обратно
... прочитам датотека и променам стринг
... креирам ZIP датотека
... поврзам Apache и Tomcat користејќи mod_jk
... пратам недефиниран број на атрибути до некоја метода
повеќе...
Java преку примери
new Socket(String addr,int port)
new URL(String address)
new URL(String protocol, String host, int port, String file)
CommPort: getInputStream()
CommPortIdentifier: getPortIdentifiers()
Statement: executeQuery(String sql)
Statement: getMaxRows()
повеќе...
Грешка
Нов напис
Рубрика:
Наслов:
  
  

страна број:123
Единствен Јава објект (singleton) - Дополнување
Целта на синхронизирањето е да не инстанцираме повеќе од една инстанца од MojSingleton(). После првото повикување на getInstance() локалната променлива instance е иницијализирана и дури и повеќе нишки да го пристапат методот getInstnace() во исто време, не би имале никакви проблеми. Ајде да пробаме да го синхронизираме делот кој што го инстанцира објектот од тип MojSingleton() и да го тргнеме зборот synchronized од дефицијата на методот getInstance(). Следниов пример користи синхронизиран блок наместо синхронизиран метод:

public static MojSingleton getInstance () {
    if (instance == null) {
        synchronized (MojSingleton.class) {
            instance = new MojSingleton();
        }
    }
    return instance;
}

Не е тешко да заклучите дека овој пример ни оддалеку не ги решава нашите проблеми. Всушност овој пример го има истиот проблем како и првиот пример, кога станува збор за thread-safe пристап. Нишка 1 може да влезе во IF наредбата и да ги заврши своите циклуси пред да може да го започне синхронизираниот блок. Нишка 2 може да го изврши методот getInstance() пред нишка 1 да се разбуди. По будењето, нишка 1 ќе креира нова инстанца од MojSingleton(). Но придобивката од овој пример е што кодот не носи поблиску кон решение кое ќе работи. Во наредниот пример ќе се запознаеме со double-checked locking:

public static MojSingleton getInstance () {
    if (instance == null) {
        synchronized (MojSingleton.class) {
            if (instance == null) {
                instance = new MojSingleton();
            }
        }
    }
    return instance;
}

Што е разликата и зошто овој пример нема проблеми со thread-safety? На некој начин, овој пример е комбинација од првиот и вториот пример. Првиот пример имаше брзо извршување, но не беше thread-safe, додека вториот пример беше thread-safe но имаше проблеми со брзина на извршување. Комбинацијава е threadsafe и згора на тоа нема проблеми со брзина на извршување, односно не користи синхронизиран метод.

Преку користење на синхронизиран блок наместо метод и користење на две IF наредби гарантираме дека само една нишка ќе може да креира инстанца од MojSingleton(). Доколку една нишка влезе во синхронизираниот блок, другата нишка ќе мора да чека пред синхронизираниот блок. Да речеме дека нишка 1 е веќе во синхронизираниот блок и ги губи своите циклуси пред да креира инстанца од MojSingleton(). Нишка 2 проверува дека instance е сеуште null и застанува пред синхронизираниот блок бидејќи нишка 1 е веќе во синхронизираниот блок. Контролата се пренесува на нишка 1 која креира инстанца од MojSingleton() и го завршува методот. Нишка 2 се буди, влегува во синхронизираниот блок и ја изврпува втората IF наредба. Нишка 2 утврдува дека instance е веќе креирана (не е null) и не креира нова инстанца. Значи со користење на двете IF наредби и синхронизиран блок (double-checked locking) успеавме да креираме thread-safe синглетон. Крај на нашите маки. Јава програмерите веруваа дека ова е перфектно thread-safe синглетон, се додека неколку истражувачи не докажаа дека овој пример не работи, колку и да звучи бизарно. Беше утврдено дека кај некои виртуелени машини овој пример не работи
поради феномен наречен out-of-order write.

Проблемот е со меморискиот модел на Јава. Доколку нишка 1 започне со извршувањето на конструкторот MojSingleton() променливата instance добива non-null вредност. Проблемот е во тоа што instance добива non-null вредност пред да заврши изврпувањето на конструкторот MojSingleton(). Да речеме дека нишка 1 ги искористи своите циклуси пред да може да го заврши извршувањето на MojSingleton(). Нишка 2 проверува дали instance е null. Проблемот е во тоа што instance не е null иако не е комплетно иницијализирана. Бидејќи instance е non-null, нишка 2 ја враќа како резултат инстанцата која што е не целосно иницијализирана. Проблемите со double-checked locking најдобро се претставени во: http://www.ibm.com/developerworks/library/j-dcl.html.

Добрите вести се дека проблемите со double-checked locking се поправени со JSR-133 http://jcp.org/en/jsr/detail?id=133.
Тоа значи дека JRE 1.5 и понови не треба да го имаат овој проблем. Лошите вести се дека не може да знаете која виртуелна
машина ќе биде користена за извршување на вашите програми. Всушност повеќето големи компании многу ретко ги менуваат верзиите на виртуелната машина што ги користат и може сеуште да користат JRE 1.4 во нивните дата центри. Дали има thread-safe решение кое работи во било која виртуелна машина без користење на синхронизиран метод?

public class MojSingleton{

    private static MojSingleton instance = new MojSingleton();
   
    private MojSingleton() {
        ...
    }
   
    public static MojSingleton getInstance () {
        return instance;
    }
    ...
    ...
}

Верувале или не, погоре прикажаниот пример е thread-safe, колку и да е едноставен. Бидејќи instance е статичен член на класата MojSingleton(), виртуелната машина ќе ја изврши наредбата:

private static MojSingleton instance = new MojSingleton();

само еднаш. Таа наредба ќе се изврши при внесувањето на класата MojSingleton() во меморијата на виртуелната машина. Без разлика колку нишки ќе го повикаат getInstance(), статичните членови на MojSingleton() се иницијализираат еднаш и само еднаш. Пред и да може да започне извршувањето на getInstance() од било која нишка, instance ќе биде веќе иницијализирана.

Заклучок:
  • Доколку немате проблеми со повикување на методот getInstance() од премногу нишки во исто време тогаш користете synchronized метод.
  • Доколку не саката да користите synchronized метод, а вашиот код ќе биде извршуван во JRE 1.5 или понова, тогаш користете double-checked locking.
  • Доколку не саката да користите synchronized метод, а не може да гарантирате дека вашиот код ќе биде извршуван во JRE 1.5 или понова, тогаш користете статичка иницијализација.

Автор:    Славе Јовановски   
Датум:    28.01.2008
страна број: 1 2 << претходна страна :
 
Коментирај
автор: Анонимус
Анонимните коментари ќе бидат објавувани веднаш после нивната проверка.
За да вашиот коментар биде веднаш валиден претходно пријавете се или креирајте свој профил


пребарување
најди
 
Форум
 
JugMK
GetJava Download Button
http://www.eclipse.org
 
 
 
 
Copyrights © 2006 - 2017 by Java.com.mk
Права и правила за користење на java.com.mk
Контакт адреса:
contact AT java.com.mk
Powered by Supernova v.0.70 beta
JavaTM и Java-базираните ознаки се трговски марки или регистрирани трговски марки на Sun Microsystems, Inc. во САД и други држави. Java.com.mk никако не соработува со Sun Microsystems, Inc.
Сите други трговски марки се сопственост на нивните сопственици.