【问题标题】:Scope of the Java System PropertiesJava 系统属性的范围
【发布时间】:2010-10-28 21:03:33
【问题描述】:

在 Java 中,我们使用 System.setProperty() 方法来设置一些系统属性。根据this article 的说法,系统属性的使用有点棘手。

System.setProperty() 可能是一个邪恶的调用。

  • 它是 100% 线程敌对的
  • 它包含超全局变量
  • 当这些变量神秘莫测时,调试起来非常困难 在运行时更改。

我的问题如下。

  1. 系统属性的范围如何?它们是特定于每个虚拟机的,还是具有“超级全局性质”,在每个虚拟机实例上共享相同的一组属性?我猜选项 1

  2. 是否有任何工具可用于监视运行时更改以检测系统属性中的更改。 (只是为了方便问题检测)

【问题讨论】:

    标签: java jvm system-properties


    【解决方案1】:

    系统属性是每个进程的。这意味着它们比静态字段更具全局性,静态字段是每个类加载器。例如,如果您有一个运行多个 Java webapps 的 Tomcat 实例,每个实例都有一个类 com.example.Example 和一个名为 globalField 的静态字段,那么 webapps 将共享系统属性,但可以设置 com.example.Example.globalField在每个 webapp 中设置不同的值。

    【讨论】:

    • @Dejel 它们不是线程本地的。同一 JVM 进程中的所有线程都有一组共享的系统属性值。
    【解决方案2】:

    当你启动一个新的 JVM 时,它会复制一份环境变量,并在它的所有生命周期中使用它们。因此,如果您对该环境进行更改,它们将仍然局限于此。 我遇到并正在调查的奇怪行为略有不同:如果我启动一个 JVM,它声明了一些影响我在应用程序中使用的库的行为的环境变量(cmd 行上的 -D 参数)。但是,如果在 java 代码中(它们是可见的),我对它们进行了更改,那么这些更改似乎不会影响库的行为。奇怪的是我们在同一个JVM!

    【讨论】:

    【解决方案3】:

    每个 VM 有一份属性副本。它们与其他静态(包括单例)有很多相同的问题。

    我想,作为一个 hack,你调用 System.setPropertiesProperties 的一个版本,它会根据上下文(线程、调用堆栈、一天中的时间等)做出不同的响应。它还可以使用System.setProperty 记录任何更改。您还可以为相关权限设置SecurityManager 日志安全检查。

    【讨论】:

      【解决方案4】:

      你没有说你使用系统属性的动机是什么。

      我们使用 Spring 进行配置,并使用注入 XML 的属性文件设置初始属性。在应用程序运行时更改配置是使用 JMX 进行的。

      当然,还有许多其他方法可以使用属性文件、基于 xml 的配置等更改 Java 中的配置。

      【讨论】:

        【解决方案5】:

        系统属性的范围

        至少通过阅读System.setProperties 方法的 API 规范,我无法得到系统属性是否由 JVM 的所有实例共享的答案。

        为了找出答案,我编写了两个快速程序,它们将通过System.setProperty 设置系统属性,使用相同的键,但值不同:

        class T1 {
          public static void main(String[] s) {
            System.setProperty("dummy.property", "42");
        
            // Keep printing value of "dummy.property" forever.
            while (true) {
              System.out.println(System.getProperty("dummy.property"));
              try {
                Thread.sleep(500);
              } catch (Exception e) {}
            }
          }
        }
        
        class T2 {
          public static void main(String[] s) {
            System.setProperty("dummy.property", "52");
        
            // Keep printing value of "dummy.property" forever.
            while (true) {
              System.out.println(System.getProperty("dummy.property"));
              try {
                Thread.sleep(500);
              } catch (Exception e) {}
            }
          }
        }
        

        (请注意,运行上面的两个程序会使它们陷入无限循环!)

        事实证明,当使用两个独立的java进程运行这两个程序时,一个JVM进程中设置的属性值不会影响另一个JVM进程的值。

        我应该补充一点,这是使用 Sun 的 JRE 1.6.0_12 的结果,并且这种行为至少在 API 规范中没有定义(或者我无法找到它),行为可能会有所不同。

        是否有任何工具可以监控运行时变化

        据我所知。但是,如果确实需要检查系统属性是否有更改,则可以一次保留Properties 的副本,并将其与对System.getProperties 的另一个调用进行比较——毕竟PropertiesHashtable 的子类,因此将以类似的方式进行比较。

        下面的程序演示了一种检查系统属性是否发生变化的方法。可能不是一个优雅的方法,但它似乎完成了它的工作:

        import java.util.*;
        
        class CheckChanges {
        
          private static boolean isDifferent(Properties p1, Properties p2) {
            Set<Map.Entry<Object, Object>> p1EntrySet = p1.entrySet();
            Set<Map.Entry<Object, Object>> p2EntrySet = p2.entrySet();
        
            // Check that the key/value pairs are the same in the entry sets
            // obtained from the two Properties.
            // If there is an difference, return true.
            for (Map.Entry<Object, Object> e : p1EntrySet) {
              if (!p2EntrySet.contains(e))
                return true;
            }
            for (Map.Entry<Object, Object> e : p2EntrySet) {
              if (!p1EntrySet.contains(e))
                return true;
            }
        
            return false;
          }
        
          public static void main(String[] s)
          {
            // System properties prior to modification.
            Properties p = (Properties)System.getProperties().clone();
            // Modification of system properties.
            System.setProperty("dummy.property", "42");
            // See if there was modification. The output is "false"
            System.out.println(isDifferent(p, System.getProperties()));
          }
        }
        

        属性不是线程安全的?

        Hashtable 是线程安全的,所以我期待Properties 也是如此,事实上,Properties 类的 API 规范证实了这一点:

        这个类是线程安全的:多个 线程可以共享一个Properties 对象无需外部 同步。,Serialized Form

        【讨论】:

          【解决方案6】:

          它们的范围是正在运行的 JVM,但除非您有一些深奥的类加载器问题,否则带有属性对象的静态变量将执行相同的操作,并有机会同步或执行您需要的任何其他操作。

          【讨论】:

            【解决方案7】:

            是的,“系统属性”是每个虚拟机的(尽管有许多“神奇”属性包含有关主机系统的信息,例如:“os.name”、“os.arch”等)。

            至于您的第二个问题:我不知道有这样的工具,但如果您担心系统属性会被更改,您可以使用特殊的SecurityManager 来防止(甚至可能跟踪)系统属性更改。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2012-04-16
              • 1970-01-01
              • 2010-10-02
              • 2011-08-06
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-03-12
              相关资源
              最近更新 更多