LINUX.ORG.RU

[java] lazy initialization

 


0

1

Здравствуйте!
Как в java правильно сделать lazy initialization?

Сначала было сделано так:

public class ServicesFactory {
    private static ServicesFactory instance = null;
    private static ImagesService imagesService = null;
    
    public static synchronized ServicesFactory getInstance() {
        if (instance == null) {
            instance = new ServicesFactory();
        }
        return instance;
    }
    
    public ImagesService getImagesService() {
        if (imagesService == null) {
            imagesService = new DefImagesServiceImpl();
        }
        return imagesService;
    }

}
PMD ругался на incorrect lazy initialization.

Сделал так:
public class ServicesFactory {
    private static ServicesFactory instance = null;
    private static ImagesService imagesService = null;
    
    public static synchronized ServicesFactory getInstance() {
        if (instance == null) {
            instance = new ServicesFactory();
        }
        return instance;
    }
    
    public synchronized ImagesService getImagesService() {
        if (imagesService == null) {
            imagesService = new DefImagesServiceImpl();
        }
        return imagesService;
    }

}
Ругаться перестал.

Но, по ссылке http://en.wikipedia.org/wiki/Double-checked_locking написано:
// Correct lazy initialization in Java
// This relies on the fact that inner classes are not loaded until they are referenced.
@ThreadSafe
class Foo {
    private static class HelperHolder {
       public static Helper helper = new Helper();
    }
 
    public static Helper getHelper() {
        return HelperHolder.helper;
    }
}
Как все-таки по-правильному?

★★★★★

Прикрутить Spring и воспользоваться <bean ... lazy-init=«true»/>

CARS ★★★★
()

Да оба варианты правильны. Во втором варианте нет synchronized, поэтому может быть быстрее, если это критично.

roy ★★★★★
()

ImagesService зачем static, а getter к нему не static? Надо определиться.

Вариант с subclass'ом эффективнее.

maxcom ★★★★★
()
Ответ на: комментарий от maxcom

Т.е. он и thread-safe, и не требуется никаких synchronized/volatile, и быстрее? А какие-нибудь минусы? Или это лучший вариант?

kovrik ★★★★★
() автор топика
Ответ на: комментарий от maxcom

Еще в вики прочитал про «The Enum way» Singletone'а.
Как он?

Допустим, если в итоге сделать так:

public enum ServicesFactory {
    INSTANCE;

    private static class StatisticsServiceHolder {
       public static StatisticsService statisticsService = new DefStatisticsServiceImpl();
    }

    public static StatisticsService getStatisticsService() {
        return StatisticsServiceHolder.statisticsService;
    }

    private static class ImagesServiceHolder {
       public static ImagesService imagesService = new DefImagesServiceImpl();
    }

    public static ImagesService getImagesService() {
        return ImagesServiceHolder.imagesService;
    }
}
1. С точки зрения 'правильности' реализации шаблона одиночка, с точки зрения потокобезопасности и т.д.?

2. Почему в:

@ThreadSafe
class Foo {
    private static class HelperHolder {
       public static Helper helper = new Helper();
    }
 
    public static Helper getHelper() {
        return HelperHolder.helper;
    }
}
в subclass'е HelperHolder'е Helper объявлен как public, а не private?

kovrik ★★★★★
() автор топика

На хабрахабр прямо пару дней назад была запись о синглтонах и ленивой инициализации оных в яве.

note173 ★★★★★
()
Ответ на: комментарий от kovrik

Добавлю:
PMD предупреждает, что все методы статические, поэтому лучше использовать Singleton, либо сделать класс абстрактным, либо добавить private конструктор.
Как лучше сделать все-таки?
1. Singleton-вариант выше с enum'ом?
2. Объявить класс абстрактным?
3. Сделать ему private конструктор?

kovrik ★★★★★
() автор топика
Ответ на: комментарий от kovrik

> в subclass'е HelperHolder'е Helper объявлен как public, а не private?

С private тоже будет работать, но все равно к нему доступа снаружи класса нет, насколько я помню, правила для него как для обычного члена.

note173 ★★★★★
()
Ответ на: комментарий от kovrik

Вложенный класс может использовать private элементы внешнего, а внешний — private элементы внутреннего. Не знаю, почему так, и лень искать в спецификации, но оно работает...

note173 ★★★★★
()
Ответ на: комментарий от kovrik

Ну синглтон не должен давать возможности другим создавать себя, в т.ч. через new. Я обычно делаю приватный конструктор. Вариант с енумом интересен, но непонятен смысл. Всё же енум это не просто конструкция, а целый класс, от которого наследуешься. Надо ли оно, когда можно без этого?

roy ★★★★★
()
Ответ на: комментарий от kovrik

И вообще, если использовать enum-based singleton, то нужны ли эти holder'ы? Скажем, так:

public enum ServicesFactory {
    INSTANCE;
    public static ImagesService imagesService = new DefImagesServiceImpl();
}
А вызывать:
ServicesFactory.imagesService.... ?

Насчет enum-based singleton, пишут:

"This approach is functionally equivalent to the public field approach, except that it is more concise, provides the serialization machinery for free, and provides an ironclad guarantee against multiple instantiation, even in the face of sophisticated serialization or reflection attacks. While this approach has yet to be widely adopted, a single-element enum type is the best way to implement a singleton."

kovrik ★★★★★
() автор топика

В общем, в итоге, получился такой вариант:

public enum ServicesFactory {
    INSTANCE;

    private static class StatisticsServiceHolder {
       static final StatisticsService statisticsService = new DefStatisticsServiceImpl();
    }

    public static StatisticsService getStatisticsService() {
        return StatisticsServiceHolder.statisticsService;
    }

    private static class MetricsServiceHolder {
       static final MetricsService metricsService = new DefMetricsServiceImpl();
    }

    public static MetricsService getMetricsService() {
        return MetricsServiceHolder.metricsService;
    }

    private static class ImagesServiceHolder {
       static final ImagesService imagesService = new DefImagesServiceImpl();
    }

    public static ImagesService getImagesService() {
        return ImagesServiceHolder.imagesService;
    }
    
    // ... и т.Д.
}

kovrik ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.