在Java中,我们使用System.setProperty()方法来设置一些系统属性。根据{{3}},使用系统属性有点棘手。
System.setProperty()可能是一个邪恶的调用。
- 这是100%线程敌对
- 它包含超全局变量
- 当这些变量神秘地调试时非常困难 在运行时更改。
我的问题如下。
系统属性的范围如何?它们是否特定于每个虚拟机,或者它们具有“超级全局特性”,它在每个虚拟机实例上共享相同的属性集?我猜选项1
是否有任何工具可用于监视运行时更改以检测系统属性中的更改。 (仅为了便于检测问题)
答案 0 :(得分:41)
系统属性的范围
至少从阅读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
对象无需外部 同步。,Serialized Form
答案 1 :(得分:9)
系统属性是按进程进行的。这意味着它们比静态字段更全局,静态字段是每个类加载器。因此,例如,如果您有一个运行多个Java Web应用程序的Tomcat实例,每个实例都有一个类com.example.Example
,其静态字段名为globalField
,那么webapps将共享系统属性,但是{{ 1}}可以在每个webapp中设置为不同的值。
答案 2 :(得分:4)
每个VM有一个属性副本。他们与其他静力学(包括单身人士)有很多相同的问题。
我想,作为一个黑客,你将System.setProperties
调用Properties
版本,根据上下文(线程,调用堆栈,一天中的时间等)响应不同。它还可以使用System.setProperty
记录任何更改。您还可以为相关权限设置SecurityManager
日志安全检查。
答案 3 :(得分:3)
是的,“系统属性”是每个VM(尽管有许多“魔术”属性包含有关主机系统的信息,例如:“os.name”,“os.arch”等)。
关于你的第二个问题:我不知道这样的工具,但如果你担心邻近的系统属性会发生变化,你可以使用特殊的SecurityManager来防止(甚至可能跟踪)系统属性的变化
答案 4 :(得分:3)
它们的范围是正在运行的JVM,但除非你有一些深奥的类加载器问题,否则带有属性对象的静态变量将做同样的事情,并有机会同步或做你需要的任何其他事情。
答案 5 :(得分:0)
您没有说明使用系统属性的动机是什么。
我们使用Spring进行配置,并使用注入XML的属性文件设置初始属性。应用程序运行时对配置的更改是使用JMX进行的。
当然,还有许多其他方法可以使用属性文件,基于xml的配置等来更改Java中的配置。
答案 6 :(得分:0)
当你启动一个新的JVM时,它会复制环境变量并将它们用于它的所有生命周期。因此,如果您对该环境进行了更改,它们仍然会受到限制。 我遇到的奇怪行为和我正在调查的行为略有不同:如果我启动一个JVM,声明一些环境变量(cmd行上的-D参数),这会影响我在我的应用程序中使用的库的行为。但是,如果在java代码中(它们是可见的),我对它们进行了更改,似乎这些更改不会影响库的行为。奇怪的是我们在同一个JVM中!