Объем переменных статического класса в 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... Но это просто предположение.
Спасибо за любую помощь.
Ответы
Ответ 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, а не в приложение.