[英]Scope of the Java System Properties
在Java中,我們使用System.setProperty()方法來設置一些系統屬性。 根據這篇文章 ,使用系統屬性有點棘手。
System.setProperty()可能是一個邪惡的調用。
- 這是100%線程敵對
- 它包含超全局變量
- 當這些變量在運行時神秘地改變時,調試極其困難。
我的問題如下。
系統屬性的范圍如何? 它們是否特定於每個虛擬機,或者它們具有“超級全局特性”,它在每個虛擬機實例上共享相同的屬性集? 我猜選項1
是否有任何工具可用於監視運行時更改以檢測系統屬性中的更改。 (僅為了便於檢測問題)
系統屬性的范圍
至少從閱讀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.