簡體   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