2015-06-02 32 views
8

Sto giocando con la versione a tempo di wait() in java.lang.Object e ho osservato che agisce in modo diverso in due diversi scenari.Running wait() su un'istanza di Thread da main() in Java

Scenario1: Utilizzando la definizione di default di run() nella Discussione

public static void main (String[] args) throws InterruptedException { 
    Thread t = new Thread();  
    t.start(); 
    System.out.print("X"); 
    synchronized(t) { t.wait(10000);} 
    System.out.print("Y"); 
} 

Domande su scenario1: sto sperimentando un ritardo tra X e Y. E 'questa attesa perché sto chiamando() da main (anche se, su t) e quindi lo stack di chiamate del thread principale viene utilizzato, piuttosto che quello del secondo thread?

Scenario2:Sottoclasse Filettatura al volo per eseguire l'override di esecuzione() per stampare qualcosa.

public static void main (String[] args) throws InterruptedException { 
    Thread t = new Thread() {public void run() 
        {System.out.print("I am the second thread.");}}; 
    t.start(); 
    System.out.print("X"); 
    synchronized(t) { t.wait(10000);} 
    System.out.print("Y"); 
} 

Domande su scenario2: NON sto sperimentando ogni ritardo a tutti! Cosa è cambiato solo perché ho eseguito overridden()? Ora, ogni volta che eseguo il programma, stampa immediatamente "XI am the second thread.Y" senza alcun ritardo, qualunque cosa! Dove è andato a finire l'effetto di wait()?

+0

Perché utilizzare "l'implementazione predefinita di esecuzione" in una discussione? – Patrick

+0

@Patrick: solo per testare il threading in Java, nient'altro. – softwarelover

+0

Non riesco a riprodurre i risultati con lo scenario 2 come descritto. C'è qualcosa che sta accadendo nel tuo ambiente, o con la classe che lo racchiude. – jdv

risposta

1

Il explanation about how the thread finishing sends a notifyAll è pertinente e corretto, +1 da me. Proverò ad aggiungere alcune informazioni sul perché questo è rilevante.

Quando si chiama

synchronized(t) { t.wait(10000);} 

nel thread principale, è il filo conduttore che fa l'attesa. t è il monitor su cui è in attesa il thread principale. La tua aspettativa che questo dovrebbe rendere il thread t andare in sospeso è sbagliato.

Il monitor here (l'oggetto condiviso essendo bloccato su, che risulta essere t) è utilizzato per la comunicazione tra i vari fili, un thread chiama notifyAll sul monitor e gli altri thread in attesa sul monitor riceve la notifica. Puoi pensare al monitor come a un punto di comunicazione condiviso.

Nel primo esempio, il thread t inizia e termina immediatamente (perché non ha nulla da fare). Il thread termina e invia la sua notifica prima che il thread principale inizi ad attendere, quindi viene visualizzato un ritardo fino a quando scade l'attesa.

Nel secondo esempio, il thread t ha qualcosa da stampare, c'è una condizione di competizione tra esso e il thread principale. È un free-for-all, ciò che accade in primo luogo dipende dagli incidenti del tempismo. Quello che vedi è che il thread t ora deve stampare una riga sulla console, quindi riesce a rimanere occupato abbastanza a lungo da essere ancora attivo nel momento in cui il thread principale inizia ad attendere, consentendo al thread principale di ricevere la notifica quando t termina, il thread principale ne interrompe l'attesa.

+0

In realtà, mi sto preparando per l'esame OCP Java 7 e mi sono imbattuto in un esempio di problema che mi ha portato a scrivere questo post. Non ho intenzione di usare join() o qualcosa del genere. La domanda di esempio fornisce lo scenario1 con run predefinito() e chiede di scegliere una risposta (D è corretta) dal basso: A. Stampa X e esce. B. Stampa X e non esce mai. C. Stampa XY ed esce quasi immediatamente. D. Stampa XY con un ritardo di 10 secondi tra X e Y. E. Stampa XY con un ritardo di 10000 secondi tra X e Y. F. Il codice non viene compilato. G. Un'eccezione viene generata in fase di esecuzione. – softwarelover

+0

@softwarelover: sembra un errore, D non è corretto. –

+0

Scenario1, ovvero. Sto usando il compilatore online ideone.com. – softwarelover

6

Si è incappato esattamente nel motivo per cui non si dovrebbe MAI chiamare wait o notify(All) su Thread (vedere JavaDocs per Thread). Internamente, Thread utilizza wait e notifyAll per implementare Thread.join(), quindi cosa succede nel secondo caso il thread entra in attesa, ma poi l'altro thread muore e chiama notifyAll(), che riattiva il thread principale.

Utilizzare Thread.sleep se si desidera attendere un tempo trascorso, utilizzare Thread.join se si desidera effettivamente attendere la chiusura del thread. Inoltre, leggi javadocs in Object per l'uso corretto di wait, notify e notifyAll.

javaDoc:

public final void join(long millis) 
       throws InterruptedException 

Waits al massimo Millis millisecondi per questo thread morire. Un timeout di 0 significa aspettare per sempre. Questa implementazione utilizza un ciclo di chiamate this.wait condizionate su this.isive. Quando un thread termina il metodo , viene invocato il metodo this.notifyAll. Si consiglia alle applicazioni di non utilizzare le istanze wait, notify o notifyAll on Thread.

+0

Va notato che questo dipende da un timing imprevedibile. Se il thread è già morto al momento, viene richiamato 'wait', non c'è ulteriore notifica e, quindi, il chiamante attenderà il tempo pieno. Pertanto, se si prevede di attendere la terminazione, è necessario utilizzare 'join'. – Holger

+0

Non è mai tanto tempo. Puoi (e le persone lo fanno) scrivere un programma che chiama 'someThread.wait()' e 'someThread.notify()', e fintanto che il programma usa il pattern di attesa cannonica wait()/notify(), allora funzionerà correttamente anche a dispetto del fatto che anche la classe Thread aspetta() s e notify() s lo stesso oggetto. È comunque privo di senso, e di cattivo stile, e parlando come membro di un grande team di sviluppo software, non permetterei a nessuno dei miei colleghi di controllare il codice che lo ha fatto. –

+0

@jameslarge sì, hai ragione - potrebbe essere usato correttamente, e ovviamente ci sono momenti in cui vuoi/devi usare i monitor di thread per sincronizzarli correttamente. Ma in tutte le situazioni che ho mai incontrato, puoi perfettamente usare un altro oggetto (come un'istanza di programma 'Object') per il monitor senza aggiungere un comportamento inaspettato nel modo in cui Thread lo utilizza. – ControlAltDel