Java中静态类变量的范围

Sco*_* C. 12 java scope static-members

我在我的日志记录类中定义了一个静态对象,其行如下:

   class myLoggingClass {
     static java.util.Properties properties;
     ...
     ...
   }
Run Code Online (Sandbox Code Playgroud)

根据我的参考书,这意味着属性对象由我的类的所有实例共享.

我觉得这个定义不够.我正在编写一个在我们项目的每个应用程序中多次调用的类.

此外,我们的项目使用在同一个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中使用的静态对象没有相同的范围级别......但这只是猜测.

谢谢你的帮助.

Jon*_*eet 18

静态不是"所有类的实例共享" - 它们实例无关 ; 它们属于该类型本身.特别是,静态变量在没有创建任何实例的情况下完全可用.

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

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

查看Tomcat文档,了解库的布局方式以及它们与类加载器的关系.例如,这里是Tomcat 6.0 ClassLoader的操作指南,以及5.5的等价物.

您的布尔"锁定"如何工作?你应该使用一个正确的lock(synchronized)来确保每次使用属性对象(包括读取和写入,包括在整个迭代过程中锁定)都被适当地锁定.

Properties您是否考虑将其视为不可变的,而不是更改"实时" 对象 - 因此,当您想要更新属性时,您需要复制,更改它,然后将副本设置为"实时"版本?你仍然需要阻止两个不同的线程同时进行更改(或者你会丢失一些),但它可能会使阅读方面更容易,更有效.


Gre*_*ill 5

您可能会发现,对于static已加载您的类的ClassLoader,此类变量的范围仅限于一个.我不确定Tomcat如何安排其ClassLoader,因此很难说该范围在该环境中的范围.


mat*_*t b 3

可能的原因ConcurrentModificationException是您在一个线程中迭代Properties对象的值/条目,而另一个线程同时修改它。你不可以做这个。

您能否详细说明一下您在这里提到的锁定机制:

当我的类更新它时,我使用静态布尔变量来“锁定”属性对象,但这并不能阻止异常的发生。

因为听起来不像是在使用 Java 中内置的锁定和同步方法。

像这样的事情应该可以防止线程在另一个线程更新它时读取 Properties 对象:

static Object lockObject = new Object();

...

synchronized(lockObject) {
     // access the Properties object
}
Run Code Online (Sandbox Code Playgroud)

请注意,每次访问 Properties 对象(读取或修改它)时都需要执行此操作。

另外,我永远不会推荐静态对象在所有实例或静态 lockObjects 之间共享数据 - 全局数据是邪恶的 - 但听起来好像你出于某种原因需要它。