Подтвердить что ты не робот

Объем переменных статического класса в Java

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

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

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

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

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

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

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

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

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

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

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

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

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

4b9b3361

Ответ 1

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

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

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

?

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

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

static Object lockObject = new Object();

...

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

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

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

Ответ 2

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

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

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

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

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

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

Ответ 3

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

Ответ 4

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