2015-05-08 24 views
5

Il codice seguente viene da java.lang.System.console() metodo:Possibile bug JDK in System.Console()

private static volatile Console cons = null; 

/** 
* Returns the unique {@link java.io.Console Console} object associated 
* with the current Java virtual machine, if any. 
* 
* @return The system console, if any, otherwise <tt>null</tt>. 
* 
* @since 1.6 
*/ 
public static Console console() { 
    if (cons == null) { 
     synchronized (System.class) { 
      cons = sun.misc.SharedSecrets.getJavaIOAccess().console(); 
     } 
    } 
    return cons; 
} 

A mio avviso, questi è un bug in questo metodo. dovremmo scrivere in questo modo:

public static Console console() { 
    if (cons == null) { 
     synchronized (System.class) { 
      if (cons == null) 
       cons = sun.misc.SharedSecrets.getJavaIOAccess().console(); 
     } 
    } 
    return cons; 
} 

ho ragione? Qual'è la tua opinione?

risposta

3

Se si guarda nel implementation di JavaIOAccess, vi accorgerete che c'è un null-controllo al suo interno:

public Console console() { 
    if (istty()) { 
     if (cons == null) 
      cons = new Console(); 
      return cons; 
     } 
    return null; 
} 

Poiché questo metodo è l'unico modo per inizializzare quella variabile, allora non è un problema che il controllo nullo nidificato si trova in un altro metodo. È ancora impossibile ottenere due distinti oggetti Console.

+0

JavaIoAccess è solo un'interfaccia. Le implementazioni di console() possono variare. –

+1

Non lo sono. È un codice JDK interno e un'interfaccia JDK interna. In JDK c'è solo un'implementazione. Se provi a sostituirlo con la tua implementazione, allora stai usando Java in modo non documentato, quindi nulla sarà garantito. In ogni caso non sarai in grado di creare un nuovo oggetto 'Console' dato che la classe' Console' è definitiva e ha solo un costruttore privato. Ovviamente puoi giocare con la riflessione per accedere a un costruttore privato o usare un altro modo per sparare a una gamba, ma dicendo che qualcosa di impossibile intendo "impossibile se stai usando Java in modo documentato" vedo –

+0

. Notato! Ho pensato che potrebbe cambiare a seconda della versione di Java. Ma questo è oltre questo ambito –

4

Non lo è. È possibile assegnare un valore ad esso e già è stato inizializzato. Penso che il controllo nullo sia ridondante, è già stato controllato all'esterno e come Tagir Valeev suggested, all'interno dell'implementazione JavaIoAccess della console.

Si potrebbe pensare al conflitto di thread e poiché l'inizializzazione avviene all'interno del blocco di sincronizzazione, più thread che accedono allo stesso tempo attiveranno la reinizializzazione ridondante.

Quindi si può dire che potrebbe essere più un miglioramento ridurre l'overhead piuttosto che un bug.

Tuttavia dovresti leggere di più su Double checked locking, contiene esattamente il tuo scenario. Dettagli sotto


È interessante vedere i sottili problemi di utilizzo in J2SE 1.4 (e versioni precedenti) con vari compilatori.

Dopo J2SE 5.0 quelle problema sono stati fissati

La parola chiave volatile ora assicura che più thread gestire correttamente il istanza singleton.

Come si noterà l'oggetto statico della console è volatile.

Utilizzando l'applicazione, come descritto nel link qui sopra:

private static volatile Console cons = null; 
public static Console console() { 
    Console result = console; 
    if (result == null) { 
     synchronized (System.class) { 
      result = console; 
      if (result == null) { 
       console = result =sun.misc.SharedSecrets.getJavaIOAccess().console(); 
      } 
     } 
    } 
    return result; 
} 

si potrebbe ottenere un tale miglioramento delle prestazioni:

Nota il risultato variabile locale, che sembra inutile. Questo assicura che nei casi in cui console già inizializzato (cioè, la maggior parte del tempo ), il campo volatile è accessibile solo una volta (a causa di "ritorno risultato;" invece di "ritorno console ; "), che può migliorare le prestazioni complessive del metodo di ben il 25 per cento - nota: sostituito helper con console per chiarezza

ma non sono sicuro di come spesso consolare() viene chiamato da multipla infila il primo tempo - dopo di ciò, l'inizializzazione non è più un problema a causa del controllo nullo outter.

Questa soluzione crea anche un sovraccarico in modo che l'effettivo aumento delle prestazioni sia discutibile. Quindi il tuo suggerimento (come sopra adottato) può essere considerato al meglio un miglioramento.

+1

Grazie mille per la risposta. – yuanfang

+1

Sono molto felice di aver imparato l'abilità utilizzando un risultato di variabile locale per migliorare le prestazioni del metodo. Grazie ancora. – yuanfang

Problemi correlati