Область действия переменных статического класса в Java
-
05-07-2019 - |
Вопрос
У меня есть статический объект, определенный в моем классе ведения журнала, например:
class myLoggingClass {
static java.util.Properties properties;
...
...
}
Согласно моему справочнику, это означает, что объект свойств является общим для всех экземпляров моего класса.
Я считаю это определение недостаточным.Я пишу класс, который вызывается более одного раза в каждом приложении нашего проекта.
Кроме того, наш проект использует несколько веб-сервисов, работающих в одном контейнере Tomcat.Каждый веб-сервис может иметь несколько потоков.
Виртуальная машина Java, работающая на хосте, также может запускать одно или несколько клиентских приложений веб-службы, которые выполняются вне Tomcat.
Таким образом, согласно этому определению, у меня может быть Tomcat, запускающий несколько веб-сервисов с потоками, каждый из которых имеет несколько объектов, которые могут содержать экземпляр моего класса.
Также может быть один или два веб-клиента, работающих за пределами Tomcat, но внутри одной JVM.Бы все из этих экземпляров моего класса имеют один и тот же объект свойств?Это сделало бы его общедоступным для JVM.
Если статический объект нет В рамках JVM, кто-нибудь знает, на каком уровне будет существовать каждый из них?По одному на контейнер Tomcat?По одному на каждую веб-службу и по одному на отдельное клиентское приложение веб-службы?
Причина:Когда я обновляю свои свойства, я получаю исключение java.lang.ConcurrentUpdateException из java.util.Properties.
Я использую статическую логическую переменную, чтобы «заблокировать» объект свойств, когда мой класс его обновляет, но это не предотвращает возникновение исключения.
Это наводит меня на мысль, что статический объект, используемый в моем классе, может быть не на том же уровне области видимости, что и тот, который используется в java.util.Properties...Но это всего лишь предположение.
Спасибо за любую помощь.
Решение
Вероятная причина вашего ConcurrentModificationException
заключается в том, что вы перебираете значения/записи Properties
объект в одном потоке, в то время как другой одновременно изменяет его.Ты не сможешь это сделать.
Можете ли вы рассказать подробнее о механизме блокировки, который вы здесь упоминаете:
Я использую статическую логическую переменную, чтобы «заблокировать» объект свойств, когда мой класс его обновляет, но это не предотвращает возникновение исключения.
?
Потому что это не похоже на использование встроенных в Java методов блокировки и синхронизации.
Что-то вроде этого должно помешать потокам читать объект Properties, пока другой поток его обновляет:
static Object lockObject = new Object();
...
synchronized(lockObject) {
// access the Properties object
}
Обратите внимание, что вам нужно будет это сделать каждый время доступа к объекту «Свойства» для его чтения или изменения.
Кроме того, я бы никогда не рекомендовал статическим объектам совместно использовать данные между всеми экземплярами или статическими объектами блокировки — глобальные данные — это зло, но звучит так, как будто вам это нужно по какой-то причине.
Другие советы
Статика не "используется всеми экземплярами класса" - они не связаны с экземплярами; они принадлежат самому типу . В частности, статические переменные идеально подходят без создания каких-либо экземпляров.
Это дает ключ к пониманию области действия статики: они ограничены объектом Class
, представляющим содержащий класс, который в свою очередь ограничен ClassLoader
, который загрузил его.
В зависимости от того, где находится библиотека, статическая переменная может иметь размер JVM или веб-приложения, или, возможно, что-то среднее между ними, если Tomcat поддерживает множественный хостинг (я не могу вспомнить случайно).
Посмотрите в документации Tomcat, как расположены библиотеки и как они связаны с загрузчиками классов. Например, вот руководство Tomcat 6.0 ClassLoader и эквивалент для 5.5 .
Как ваш Boolean " заблокировать " Работа? Вы должны действительно использовать правильную блокировку ( synchronized
), чтобы убедиться, что каждое использование объекта свойств (как чтение, так и запись, включая блокировку на весь период, в течение которого вы итерируете его), надлежащим образом заблокировано. р>
Вместо изменения " live " Объект Properties
рассматривал ли вы его как неизменный - поэтому, когда вы хотите обновить свойства, вы берете копию, изменяете ее, а затем делаете копию " живой " версия? Вам по-прежнему нужно предотвращать одновременное внесение изменений в двух разных потоках (или вы их потеряете), но это, вероятно, сделает чтение намного проще и эффективнее.
Вы можете обнаружить, что область действия такой переменной static
ограничена одной на ClassLoader, который загрузил ваш класс. Я не уверен, как Tomcat упорядочивает свои ClassLoaders, поэтому трудно сказать, какой будет область действия в этой среде.
Может ли быть проблема загрузчика классов, когда jar, содержащий ваш класс, дублируется в каждом WEB-INF / lib ваших разных приложений? Если это так, я бы попытался добавить эту банку в библиотеки Tomcat, а не в приложение.