2010-07-29 8 views
20

Il ciclo while (true) { ... } non funziona correttamente? Qual è l'alternativa?Java: il ciclo `while (true) {...}` in un thread non è valido? Qual è l'alternativa?

Aggiornamento; cosa sto cercando di ...

Ho ~ 10.000 thread, ognuno consuma messaggi dalle loro code private. Ho un thread che produce i messaggi uno a uno e li inserisce nella coda corretta del consumatore. Ciascun ciclo di thread di consumo si riavvia indefinitamente, controllando che un messaggio venga visualizzato nella coda e elaborato.

All'interno Consumer.java:

@Override 
public void run() { 
    while (true) { 
     Message msg = messageQueue.poll(); 
     if (msg != null) { 
      ... // do something with the message 
     } 
    } 
} 

Il produttore sta mettendo i messaggi all'interno di code di messaggi dei consumatori ad un ritmo rapido (diversi milioni di messaggi al secondo). I consumatori dovrebbero elaborare questi messaggi il più velocemente possibile!

Nota: lo while (true) { ... } viene terminato da un messaggio KILL inviato dal produttore come ultimo messaggio. Tuttavia, la mia domanda riguarda il modo corretto di fare questo messaggio passando ...

Si prega di vedere the new question, per quanto riguarda questo disegno.

+0

Perché non fornisci maggiori dettagli su ciò che stai cercando di ottenere e ti diremo se c'è un modo migliore per farlo. – Ryan

+0

'@Ryan:' Aggiornato; per favore dai un'occhiata! –

+1

10000 thread sembra una cattiva idea, poiché potrebbe esserci un overhead associato a ciascun thread ... – Colen

risposta

7
while (!stop_running) { ... } 

... forse? Una sorta di flag di uscita viene spesso utilizzato per controllare l'esecuzione del thread.

+8

Se si esegue questa operazione, assicurarsi che stop_running utilizzi la parola chiave volatile. Vedi Concurrency In Practice Java, sezione 7.1. –

+0

questo sembra semplice, ma il problema: in che modo "stop_running' diventa falso dopo che il ciclo inizia? Questo è quello che penso che la maggior parte della gente si stia chiedendo – mmcrae

7

Non intrinsecamente, no. Puoi sempre cauzione utilizzando break o return. Assicurati di fare effettivamente (ad un certo punto)

Il problema è cosa succede quando il tuo thread non ha nulla da fare? Se ti limiti a controllare una condizione, il tuo thread mangerà tutta la CPU senza fare nulla. Quindi assicurati di usare wait per bloccare il thread, o sleep se non hai nulla su wait su.

+0

E 'davvero così tanto CPU? – Clocker

+0

@Clocker: provalo tu stesso, ma sì, credo che un'attesa indaffarata userebbe il 100% di un core della CPU. –

+0

@Clocker Si chiama _busy loop_ e utilizza tutta la potenza della CPU che può ottenere da un singolo core. Ai vecchi tempi, in cui il solo _cuo_cuo di CPU poteva portare il sistema in ginocchio, gli sviluppatori hanno quindi beneficiato enormemente di un sistema a due CPU. –

3

Dipende dalla definizione di "cattivo". Significa che la persona che cerca di leggere il codice deve cercare altrove la ragione per cui il ciclo è terminato. Questo potrebbe renderlo meno leggibile.

Questa mentalità portata all'estremo risulta nella parola chiave COMEFROM. http://en.wikipedia.org/wiki/COMEFROM

10 COMEFROM 40 
20 INPUT "WHAT IS YOUR NAME? "; A$ 
30 PRINT "HELLO, "; A$ 
40 REM 
+0

100 upvotes .. (y) per il termine COMEFROM – Nilesh

1

E 'meglio avere la condizione di terminazione sulla linea while (...), ma a volte la condizione di terminazione è qualcosa che si può provare solo qualche parte nel profondo all'interno del ciclo. Quindi questo è ciò che break è per (o eccezioni). In effetti, forse il thread deve essere eseguito per sempre fino alla chiusura del programma (con System.exit); quindi while (true) ha decisamente ragione.

Ma forse stai chiedendo cosa dovrebbe andare all'interno del ciclo. È necessario assicurarsi di includere alcune operazioni di blocco, ad es., alcune chiamate di funzione in cui il thread attenderà che qualcun altro (un'altra discussione, un altro programma, il sistema operativo) esegua qualcosa. Si tratta in genere di Condition.wait se si sta programmando con blocchi o si sta leggendo da una coda di messaggi o si sta leggendo da un file o da un socket di rete o qualche altra operazione di I/O di blocco.

Si noti che sleep è generalmente non abbastanza buono. Non puoi sapere quando altri partecipanti faranno qualcosa, quindi non c'è modo di evitare di svegliarti troppo spesso (così facendo bruciare inutilmente il tempo della CPU) o troppo raramente (quindi non reagire agli eventi in modo tempestivo). Progetta sempre il tuo sistema in modo che quando un thread ha completato il suo lavoro, esso notifica a chiunque sia in attesa di quel lavoro (spesso con Condition.signal o partecipando).

13

Anziché eseguire il ciclo per sempre e interrompere o restituire, è possibile scegliere di controllare lo stato interrotto.

while (!Thread.currentThread().isInterrupted()) { 
    try { 
     doWork(); 
     wait(1000); 
    } catch (InterruptedException ex) { 
     Thread.currentThread().interrupt(); 
    } 
} 

Se le discussioni sono attività gestite da un ExecutorService, è possibile avere tutti loro fine con grazia semplicemente chiamando shutdownNow().

+5

Meglio usare Thread.sleep (1000) di wait(), cz wait richiede che l'oggetto sia bloccato per primo. – usman

+0

Ehi. È bello ... Ma cosa succede se voglio eliminare il thread dal metodo 'update' di un osservatore ... Non so quanto tempo ci vorrà per attivare il metodo in modo che un' attesa (1000) 'casuale abbia vinto lavora qui .... –

0

Io di solito andare con una classe attributo booleano chiamato 'Fatto', allora i metodi di esecuzione i fili assomigliano

done = false; 
while(!done) { 
    // ... process stuff 
} 

È possibile quindi impostare fatto = true per uccidere il ciclo. Questo può essere fatto dall'interno del ciclo, oppure puoi avere un altro metodo che lo imposta, in modo che altri thread possano staccare la spina.

0

while (true) non è male se esiste un modo per uscire dal ciclo altrimenti la chiamata verrà eseguita indefinitamente.

Per 10000 le discussioni che fanno la chiamata while(true) è cattiva pratica ... Perché non hanno un sleep() sul filo per consentire ad altri thread per eseguire o una strategia di uscita se il filo finire in esecuzione?

-1

se fossi fare ciò che si sta parlando vorrei provare questo:

private Object lock = new Object();  

public void run(){ 
    while(true){ 
     synchronized(lock){ 
      Message msg = messageQueue.poll(); 
      if (msg != null) { 
       ... // do something with the message 
      }else{ 
       try{ 
        lock.wait(); 
       }catch(InterruptedException e){ 
        e.printStackTrace(); 
        continue; 
       } 
      } 
     } 
    } 
} 

Questo ti permette di fare in modo che non si ottiene alcun exepction modifica simultanea sul MessageQueue, così come quando c'è non è un messaggio che non si utilizzerà il tempo CPU nel ciclo while (true). Ora devi solo assicurarti che quando aggiungi qualcosa al tuo messaggio, puoi chiamare lo lock.notifyAll() in modo che il filo saprà di essere eseguito di nuovo.

+0

Non è eccezionale con una coda condivisa. –

+0

Usa LinkedBlockingQueue per il messaggio Queue e sarà thread-safe, senza bisogno del blocco o del blocco sincronizzato sopra. Basta chiamare Take anziché Poll se si vuole bloccare mentre la coda è vuota. In alternativa puoi utilizzare il sondaggio con un timeout se vuoi implementare i timeout. –

+0

Anche l'ingerenza dell'eccezione interrotta significa che il thread non può mai uscire a meno che non si verifichi una RuntimeException. –

0

Sembra che tu sia occupato ad aspettare, assumendo uno standard BlockingQueue. Utilizzare take anziché poll.

Diverso da quello, for (;;) è più bello di while (true), IMO.

+0

utilizzando take continuerai ad aspettare che il messaggio arrivi correttamente? e poll (100) attenderà solo 100 ms e continuerà l'esecuzione. Quindi, il sondaggio (100) non è meglio di quello? –

Problemi correlati