Java中静态类变量的范围

时间:2009-09-09 20:54:53

标签: java scope static-members

我在我的日志记录类中定义了一个静态对象,类似于:

   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中使用的静态对象没有相同的范围级别......但这只是猜测。

感谢您的帮助。

4 个答案:

答案 0 :(得分:18)

静态不是“所有类的实例共享” - 它们与实例无关;它们属于类型本身。特别是,如果没有创建任何实例,静态变量是完全可用的。

这给出了关于静态范围的线索:它们由表示包含类的Class对象确定范围,而该类又由加载它的ClassLoader确定范围。

根据库的放置位置,静态变量可能是JVM范围的,也可能是Web应用程序范围的 - 或者可能是介于两者之间的东西,如果Tomcat支持多个托管(我不记得了)。

查看Tomcat文档,了解库的布局方式以及它们与类加载器的关系。例如,这是Tomcat 6.0 ClassLoader how-to guidethe 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库而不是应用程序。