繁体   English   中英

Java系统属性的范围

[英]Scope of the Java System Properties

在Java中,我们使用System.setProperty()方法来设置一些系统属性。 根据这篇文章 ,使用系统属性有点棘手。

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

  • 这是100%线程敌对
  • 它包含超全局变量
  • 当这些变量在运行时神秘地改变时,调试极其困难。

我的问题如下。

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

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

系统属性的范围

至少从阅读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调用进行比较 - 毕竟, Properties是子类的一个子类。 Hashtable ,因此将以类似的方式进行比较。

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

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对象,而无需外部同步。 序列化表单

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

每个VM有一个属性副本。 他们与其他静力学(包括单身人士)有很多相同的问题。

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

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

至于你的第二个问题:我不知道这样的工具,但是如果你担心邻近的系统属性会发生变化,你可以使用一个特殊的SecurityManager来防止(甚至跟踪)系统属性的变化。

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

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM