2012-01-05 15 views
5

Modifica un valore che viene utilizzato per determinare quando un ciclo while termina in un thread separato.
Non voglio sapere come farlo funzionare. Se accedo alla prova variabile solo attraverso sincronizzate getter/setter funziona come previsto ..Strano comportamento in Java con accesso non sincronizzato in un programma di multithreading

mi sarei aspettato, se qualche lettura/scrittura comandi vengono persi a causa di concorrenza il programma a volte non termina, ma non mai lo fa. Ecco cosa mi confonde ..
Mi piacerebbe sapere perché il programma non termina mai, senza il comando di stampa. E vorrei capire perché la stampa comando cambia nulla ..

 

    public class CustomComboBoxDemo { 
     public static boolean test = true; 
     public static void main(String[] args) { 
      Thread user =new Thread(){ 
       @Override 
       public void run(){ 
        try { 
         sleep(2000); 
        } catch (InterruptedException e) {} 
        test=false; 
       } 
      }; 
      user.start(); 
      while(test) { 
       System.out.println("foo"); //Without this line the program does not terminate.. 
      } 
     } 
    } 

+0

Vedere: [Il loop non visualizza il valore modificato senza un'istruzione print] (https://stackoverflow.com/questions/25425130/loop-doesnt-see-changed-value-without-a-print-statement) – Boann

risposta

8

La spiegazione più probabile è che la variabile viene letta solo una volta, trasformando lo while in un ciclo infinito (o non operativo). Poiché non hai dichiarato come volatile, il compilatore può eseguire tale ottimizzazione.

Una volta che si chiama una funzione esterna dall'interno del loop, il compilatore non può più dimostrare che test rimane invariato tra le iterazioni del ciclo e non esegue l'ottimizzazione.

+1

Mi chiedo, è compilatore bytecode o compilatore JIT che fa questo tipo di ottimizzazione? – bezmax

+0

@Max: sul mio sistema il compilatore bytecode non lo fa, quindi deve essere il compilatore JIT. – NPE

+1

Btw, potrebbe anche essere che lo stia leggendo costantemente, ma facendolo da una cache (come un registro della CPU) che non viene modificato nella scrittura nella memoria principale. Contrassegnare il campo come "volatile" risolverà anche questo. – yshavit

0

presumo che sia qualcosa a che fare con il modo in cui viene gestita IO. Senza la stampa, probabilmente vedrai l'applicazione java usando tutto il tempo di CPU disponibile; con la stampa è probabile che i ritardi di I/O riducano il tempo di CPU per l'elaborazione.

Un modo rapido per testare questa teoria sarebbe quello di inserire printlns nel metodo run() del thread per verificare se il thread è effettivamente in esecuzione. Nella mia esperienza, infiniti cicli vuoti causano un sacco di strani comportamenti.

Detto questo, sembra di interrompere bene sul mio posto di lavoro sotto JDK 1.6.0_10_b23

+0

D'accordo con Mcfinnigan. Aggiungi alcune stampe di debug al tuo thread. Quando qualcosa non funziona come previsto, fai sempre del lavoro per dimostrare che le tue supposizioni sono corrette, in questo caso che il thread separato funziona come progettato. – Mitch

1

Se la variabile test non è definito come volatile, il compilatore probabilmente ottimizza il ciclo che contiene nessuna operazione in un ciclo while(true) per il vostro principale thread e il programma non finisce mai.

In caso contrario, il valore della variabile test viene effettivamente verificato e quando il secondo thread modifica il suo valore, il thread principale lascia il ciclo while e il programma termina.

0

Sembra che il tuo ciclo sia stato compilato in modo non corretto in un'attesa indaffarata. L'aggiunta di una parola chiave volatile al tuo booleano corregge il "problema".

0
public static boolean test = true; 
public static void main(String[] args) { 
    Thread user =new Thread(){ 
     @Override 
     public void run(){ 
      try { 
       sleep(2000); 
      } catch (InterruptedException e) {} 
      test=false; 
      System.out.println("Thread.end <"+test+">"); 
     } 
    }; 
    user.start(); 
    while(test); 
} 

Questo è interessante. Probabilmente il compilatore lo ottimizza in un ciclo infinito, senza leggere il valore ad ogni ciclo.

Definire test come volatile consente la correzione e lasciate che il vostro programma di terminare

Btw: probabilmente già sapete che si shoud utilizzare user.join() per attendere che la discussione alla fine

0

non capisco quello che stai cercando di fare usando il codice che conosci non è sincronizzato correttamente.

Come alcuni hanno segnalato, sul proprio computer il codice si comporta in modo diverso rispetto al proprio computer. Il comportamento del codice mal sincronizzato è non definito. Non ha senso cercare di capire cosa fa poiché quel comportamento cambierà con la versione o l'architettura di JVM.

Problemi correlati