2015-12-16 15 views
8

Stavo cercando di creare alcuni scenari per dimostrare problemi di visibilità durante la condivisione di variabili tra thread. E ho notato che in quasi tutti i casi che ho provato, se all'interno run() ho aggiunto un'istruzione System.out.println() nello stesso blocco di codice in cui sto usando la variabile condivisa, il problema di visibilità non è producibile. Mi impegno a fornire un esempio:Relazione tra thread e println() istruzioni

dettagli di configurazione - Oracle java6 64bit, Eclipse Juno SR 2

  • 1) con una visibilità NUMERO:

    public class NoVisibility_Demonstration extends Thread { 
    boolean keepRunning = true; 
    public static void main(String[] args) throws InterruptedException { 
        NoVisibility_Demonstration t = new NoVisibility_Demonstration(); 
        t.start(); 
        Thread.sleep(1000); 
        t.keepRunning = false; 
        System.out.println("keepRunning is false"); 
    } 
    public void run() { 
        int x = 1; 
        while (keepRunning) 
        { 
         //System.out.println("If you uncomment this line, the code will work without the visibility issue"); 
         x++; 
    
        } 
        System.out.println("x:"+x); 
    } 
    

    }

USCITA: Il thread continua a funzionare all'infinito

  • 2) SENZA VISIBILITÀ NUMERO:

lo stesso codice come sopra, con CONTO println commentata() nella corsa()

USCITA:

...

Se si disapprova questa riga, il codice funzionerà senza la questione visibilità

Se si rimuove il commento di questa linea, il codice funzionerà senza il problema di visibilità

Se si rimuove il commento di questa linea, il codice funzionerà senza il problema di visibilità

x: 19391

keepRunning is false

Da quando ho notato un comportamento simile in tutti gli esempi che ho provato, mi chiedo se ci sia un controllo di integrità dei dati da parte di JVM prima di qualsiasi operazione di I/O.

+3

L'uso di 'System.out.println()' in quel ciclo 'while' avrà un impatto abbastanza significativo sulla velocità con cui ogni iterazione del ciclo richiede il completamento.Scrivere alla console è * lento *, semplicemente incrementare una variabile 'int' è molto veloce. Solo qualcosa da tenere a mente. – JonK

+0

Oracle or Open? –

+0

oracolo ......... –

risposta

9

PrintWriter è sincronizzato

public void println(String x) { 
    synchronized(this) { 
     this.print(x); 
     this.newLine(); 
    } 
} 

Due chiamate sequenziali di System.out.println() in filo principale e nella seconda filettatura creare un ordine di sincronizzazione tra due fili. Ciò significa che tutte le azioni (nel tuo caso si tratta di aggiornamento variabile), che è accaduto nel thread principale prima di rilasciare un monitor (uscendo dal metodo sincronizzato) saranno viste dal codice, eseguite nel secondo thread dopo aver acquisito un monitor (immettere metodo sincronizzato) .

In parole semplici, sì, chiamando System.out.println() effettua questa sincronizzazione.

+0

Grazie. Molta chiarezza ora. Anche se vedo che non c'è alcun impatto su questa osservazione indipendentemente dal fatto che io commenta o meno l'istruzione println() nel thread principale. Solo println() nella corsa() causa una differenza. Inoltre, non c'è alcun impatto anche se inserisco un'istruzione println() prima di iniziare l'altro thread da main. –

+0

@BimanTripathy non ho idea del perché ottieni questi risultati. sono stabili? – AdamSkywalker

+0

sì. il comportamento viene prodotto ogni volta. vuoi dire che non stai ottenendo gli stessi risultati che sto ottenendo? –

1

Questo comportamento è specifico dell'implementazione. In OpenJDK, il corpo di viene sincronizzato sebbene lo API non dichiari che lo è.

Problemi correlati