2015-02-16 2 views
5

Questo codice da Effective Java (Articolo 66): (senza sincronizzazione o volatili questo non finisce mai)Perché il thread si comporta in modo diverso con il corpo del metodo di esecuzione diverso?

public class ThreadPractice { 
static boolean canrunstatic; 

public static void main(String[] args) throws InterruptedException { 

    Thread backgroundThread = new Thread(new Runnable() { 
     public void run() { 
      int i = 0; 
      while (!canrunstatic){i++;} 
      System.out.println("finished"); 
     } 
    }); 
    backgroundThread.start(); 
    TimeUnit.SECONDS.sleep(1); 
    canrunstatic = true; 
} 

Come Bloch menzionato nel capitolo che non potrà mai scrivere "finito" per la console. Ho giocato in giro con questa classe, e aggiungo che la linea per il metodo run eseguibile:

System.out.println("im still running"); 

Con questo ciclo while non solo incrementare i ma la stampa fuori questa stringa in ogni ciclo. Ma quello che mi fa impazzire, che in questo modo il thread si ferma dopo 1 secondo, quando il filo principale ritorna dal sonno.

modificata: (si arresta senza volatili/sincronizzazione)

public class ThreadPractice { 
static boolean canrunstatic; 


public static void main(String[] args) throws InterruptedException { 

    Thread backgroundThread = new Thread(new Runnable() { 
     public void run() { 
      int i = 0; 
      while (!canrunstatic){i++;System.out.println("im still running");} 
      System.out.println("finished"); 
     } 
    }); 
    backgroundThread.start(); 
    TimeUnit.SECONDS.sleep(1); 
    canrunstatic = true; 


} 

Allora, qual è la logica dietro questo?

risposta

4

Precisamente, si tratta solo di non garantita che il filo potrà mai fermarsi, ma è non è vietato che si ferma. La logica alla base di ciò è fornita dallo Java Memory Model, che è un argomento piuttosto complicato, ma necessario per comprendere il multithreading in Java.

Il concetto è che una scrittura in un campo non volatile di un thread è richiesta solo per essere vista da un altro thread se queste due azioni si sincronizzano tra loro. Un compilatore consente di riordinare alcune azioni se il comportamento mostrato dal thread in cui viene eseguito non cambia. Ma un altro thread potrebbe vedere questo. Quindi è necessaria la corretta sincronizzazione per dire al compilatore che il riordino non è consentito in alcune parti.

Leggi il documento completo su questo qui: JSR-133

2

La scrittura dei dati sulla console viene spesso implementata come operazione di sicurezza dei thread.

In tal caso, l'atto di scrittura dei dati sulla console può anche attivare l'aggiornamento della variabile canrunstatic come visto dallo backgroundThread.

Nota che questo non è promesso dal Modello di memoria Java, né per l'implementazione di Java System.out

+2

che non è specificato da nessuna parte nel modello di memoria. La scrittura sulla console è un'operazione esterna nel JMM, ma ciò non garantisce la sincronizzazione e le quote non creano sincronizzazioni con lo spigolo. Quindi questa non è una spiegazione per la logica dietro questo. – MinecraftShamrock

+0

Buon punto, questa è la causa, ma non è necessario che ciò accada. Ho aggiornato la risposta per riflettere questo. – Thirler