Java - синхронизация потоков в веб-приложении - PullRequest
1 голос
/ 10 февраля 2010

У меня есть веб-приложение, где я загружаю компоненты лениво. Здесь много

static Bla bla;
...    
if(bla == null) 
    bla = new Bla();

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

Ответы [ 7 ]

5 голосов
/ 10 февраля 2010

Лучшее решение для отложенной загрузки статического поля, как описано в Effective Java [2nd edition, Item 71, p. 283] и Java-параллелизм на практике [стр. 348], это идиома инициализации по требованию :

public class Something {
    private Something() {
    }

    private static class LazyHolder {
        private static final Something something = new Something();
    }

    public static Something getInstance() {
        return LazyHolder.something;
    }
}
3 голосов
/ 10 февраля 2010

Сложно использовать переменную volatile.

Это описано здесь: http://www.ibm.com/developerworks/java/library/j-dcl.html

Пример цитируемой сверху ссылки:

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;
    }
}

будет работать на 100% и будет намного более понятным (для чтения и понимания) по сравнению с двойной проверкой и другими подходами.

2 голосов
/ 10 февраля 2010

Предполагая, что вы используете Java 1.5 или более позднюю версию, вы можете сделать это:

    private static volatile Helper helper = null;

    public static Helper getHelper() {
        if (helper == null) {
            synchronized(Helper.class) {
                if (helper == null)
                    helper = new Helper();
            }
        }
        return helper;
    }

Это гарантированно является потокобезопасным.

Я рекомендую вам прочитать это, чтобы понять, почему var HASбыть волатильным, и двойная проверка для нуля фактически необходима: http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

1 голос
/ 10 февраля 2010

Ленивая инстанциация - это только часть проблемы. Как насчет доступа к этим полям?

Как правило, в приложении J2EE вы избегаете таких действий настолько, насколько это возможно, чтобы вы могли изолировать свой код от любых проблем с потоками.

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

При этом, чтобы ответить на ваш вопрос напрямую, вам необходимо убедиться, что доступ к этим полям осуществляется синхронно, как при чтении, так и при записи. Java 5 имеет лучшие возможности, чем использование синхронизированных в некоторых случаях. Я предлагаю прочитать Параллелизм Java на практике , чтобы понять эти проблемы.

0 голосов
/ 10 февраля 2010

Я бы спросил, почему вы считаете, что нужно загружать их лениво. Если это веб-приложение, и вы знаете, что вам нужны эти объекты, почему бы вам не захотеть загружать их с нетерпением после запуска приложения?

Пожалуйста, объясните, какую выгоду дает ленивая загрузка. Если он статический, есть ли вероятность, что вы не инициализируете эти объекты? Если ответ «нет», я бы бросил вызов дизайну и рекомендовал бы вам загружаться при запуске.

0 голосов
/ 10 февраля 2010

Поскольку bla является статическим, доступ к нему можно получить из разных экземпляров содержащего класса. и код как synchronized{...} или synchronized(this){...} не защищает от этого. Вы должны получить блокировку для одного и того же объекта во всех случаях, например, synchronized(bla){...}

0 голосов
/ 10 февраля 2010

Наилучший способ - заключить все в синхронизированный блок и объявить переменную volatile, например:

private static volatile Bla bla;
synchronized{
    if(bla == null) bla = new Bla();
}

Если вам действительно нужно иметь только один отдельный экземпляр, назначенный bla в любое время, когда ваше веб-приложение работает, вы должны иметь в виду тот факт, что ключевое слово static, примененное к объявлению переменной, только гарантирует быть одним на загрузчик классов , который читает определение класса определяющего его класса.

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