我在我的日志记录类中定义了一个静态对象,类似于:
class myLoggingClass {
static java.util.Properties properties;
...
...
}
根据我的参考书,这意味着属性对象由我的所有实例共享。
我觉得这个定义不够。我正在编写一个在我们项目的每个应用程序中多次调用的类。
此外,我们的项目使用在同一个tomcat容器中运行的多个Web服务。每个Web服务可能有多个线程。
主机上运行的Java虚拟机还可以运行一个或多个Web服务客户端应用程序,这些应用程序在tomcat外部运行。
因此,通过这个定义,我可能让tomcat运行带有线程的多个Web服务,每个线程都有几个对象,这些对象可能包含我的类的实例。
可能还有一个或两个Web客户端在tomcat之外运行,但在同一个JVM中。我的类的这些实例的所有会共享相同的属性对象吗?这将使其成为JVM范围。
如果静态对象不 JVM范围内,是否有人知道每个对象存在的级别?每个tomcat容器一个?每个Web服务一个,每个独立的Web服务客户端应用程序一个?
原因:当我更新我的属性时,我从java.util.Properties获得了java.lang.ConcurrentUpdateException。
我正在使用静态布尔变量来在我的类更新时“锁定”属性对象,但这并不能防止异常发生。
这让我相信我的类中使用的静态对象可能与java.util.Properties中使用的静态对象没有相同的范围级别......但这只是猜测。
感谢您的帮助。
答案 0 :(得分:18)
静态不是“所有类的实例共享” - 它们与实例无关;它们属于类型本身。特别是,如果没有创建任何实例,静态变量是完全可用的。
这给出了关于静态范围的线索:它们由表示包含类的Class
对象确定范围,而该类又由加载它的ClassLoader
确定范围。
根据库的放置位置,静态变量可能是JVM范围的,也可能是Web应用程序范围的 - 或者可能是介于两者之间的东西,如果Tomcat支持多个托管(我不记得了)。
查看Tomcat文档,了解库的布局方式以及它们与类加载器的关系。例如,这是Tomcat 6.0 ClassLoader how-to guide和the equivalent for 5.5。
您的布尔“锁定”如何工作?您应该使用正确的锁(synchronized
)来确保每次使用属性对象(包括读取和写入,包括在整个迭代期间锁定)都被适当锁定。
您没有更改“实时”Properties
对象,而是考虑将其视为不可变 - 所以当您想要更新属性时,您需要复制,更改它,然后将副本设为“直播” “版本?你仍然需要阻止两个不同的线程同时进行更改(或者你会丢失一些),但它可能会使阅读方面更容易和更有效。
答案 1 :(得分:5)
您可能会发现此类static
变量的范围仅限于已加载您的类的ClassLoader。我不确定Tomcat如何安排其ClassLoader,因此很难说该范围在该环境中的范围。
答案 2 :(得分:3)
ConcurrentModificationException
的可能原因是您在一个线程中通过Properties
对象的值/条目进行迭代,而另一个线程同时修改它。你不能这样做。
您能否详细说明您在此提及的锁定机制:
我正在使用静态布尔变量来在我的类更新时“锁定”属性对象,但这并不能防止异常发生。
因为它听起来不像是在Java中使用内置的锁定和同步方法。
这样的事情会阻止线程读取Properties对象,而另一个线程更新它:
static Object lockObject = new Object();
...
synchronized(lockObject) {
// access the Properties object
}
请注意,您需要执行每次访问Properties对象,以便阅读或修改它。
此外,我永远不会建议静态对象在所有实例或静态lockObjects之间共享数据 - 全局数据是邪恶的 - 但听起来好像你出于某种原因需要它。
答案 3 :(得分:0)
这可能是一个类加载器问题,其中包含您的类的jar在您的不同应用程序的每个WEB-INF / lib中都是重复的吗? 如果是这样,我会尝试将此jar添加到Tomcat库而不是应用程序。