Область применения статических переменных класса в Java - PullRequest
12 голосов
/ 10 сентября 2009

У меня есть статический объект, определенный в моем классе журналирования, в соответствии с:

   class myLoggingClass {
     static java.util.Properties properties;
     ...
     ...
   }

Согласно моему справочнику, это означает, что объект свойств является общим для всех экземпляров моего класса.

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

Кроме того, наш проект использует несколько веб-сервисов, работающих в одном контейнере Tomcat. Каждый веб-сервис может иметь несколько потоков.

Виртуальная машина Java, работающая на хосте, может также запускать одно или несколько клиентских приложений веб-службы, которые запускаются вне tomcat.

Так что по этому определению у меня может быть tomcat, запускающий несколько веб-сервисов с потоками, каждый из которых имеет несколько объектов, которые могут содержать экземпляр моего класса.

Может также быть один или два веб-клиента, работающих вне tomcat, но внутри одной JVM. Могут ли все этих экземпляров моего класса использовать один и тот же объект свойств? Это сделало бы его шириной JVM.

Если статический объект не JVM-широкий, кто-нибудь знает, на каком уровне каждый из них будет существовать? Один на контейнер для кота? Одна на веб-службу и одна на отдельное клиентское приложение веб-службы?

Причина: когда я обновляю свои свойства, я получаю исключение java.lang.ConcurrentUpdateException от java.util.Properties.

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

Это наводит меня на мысль, что статический объект, используемый в моем классе, может не иметь того же уровня видимости, что и используемый в java.util.Properties ... Но это всего лишь предположение.

Спасибо за любую помощь.

Ответы [ 4 ]

18 голосов
/ 10 сентября 2009

Статика не «используется всеми экземплярами класса» - она ​​ не связана с экземплярами; они принадлежат самому типу . В частности, статические переменные можно легко использовать без создания любых экземпляров.

Это дает ключ к пониманию области действия статики: они ограничены объектом Class, представляющим содержащий класс, который, в свою очередь, ограничен ClassLoader, который его загрузил.

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

Посмотрите документацию Tomcat, чтобы узнать, как расположены библиотеки и как они связаны с загрузчиками классов. Например, вот руководство по Tomcat 6.0 ClassLoader , а эквивалент для 5.5 .

Как работает ваш логический «замок»? Вы действительно должны использовать правильную блокировку (synchronized), чтобы убедиться, что каждое использование объекта свойств (как чтение, так и запись, включая блокировку на весь период, в течение которого вы итерируете его) надлежащим образом заблокировано.

Вместо изменения "живого" Properties объекта вы рассматривали его как неизменный - поэтому, когда вы хотите обновить свойства, вы берете копию, изменяете ее, а затем делаете копию "живой" версией ? Вам по-прежнему нужно предотвращать одновременное внесение изменений двумя разными потоками (или вы их потеряете), но это, вероятно, сделает чтение более простым и эффективным.

5 голосов
/ 10 сентября 2009

Вы можете обнаружить, что область действия такой переменной static ограничена одной для каждого ClassLoader, который загрузил ваш класс. Я не уверен, как Tomcat организует свои ClassLoaders, поэтому трудно сказать, какова будет область действия в этой среде.

3 голосов
/ 10 сентября 2009

Вероятная причина вашего ConcurrentModificationException в том, что вы перебираете значения / записи объекта Properties в одном потоке, в то время как другой изменяет его одновременно. Вы не можете сделать это.

Не могли бы вы подробнее рассказать о запирающем механизме, который вы упомянули здесь:

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

Потому что это не звучит так, как будто вы используете встроенные методы блокировки и синхронизации в Java.

Нечто подобное должно препятствовать тому, чтобы потоки читали объект Properties, пока другой поток обновляет его:

static Object lockObject = new Object();

...

synchronized(lockObject) {
     // access the Properties object
}

Обратите внимание, что вам нужно будет делать это каждый каждый раз, когда вы получаете доступ к объекту Properties, либо для его чтения, либо для изменения.

Кроме того, я бы никогда не рекомендовал статическим объектам обмениваться данными между всеми экземплярами или статическими объектами lockObjects - глобальные данные являются злом - но звучит так, как будто вам это нужно по какой-то причине.

0 голосов
/ 10 сентября 2009

Может ли быть проблема загрузчика классов, когда jar, содержащий ваш класс, дублируется в каждом WEB-INF / lib ваших разных приложений? Если это так, я бы попытался добавить эту банку в библиотеки Tomcat, а не в приложение.

...