2016-05-06 15 views
6

Ultimamente ho creato un programma molto semplice. Un contatore del tempo che ha la capacità di mettere in pausa. Funzionava con 3 thread, 2 per Swing e 1 per il thread principale.while (true) loop o java.util.Timer per un ciclo di programma standard?

Per questo programma ci dovrebbe essere una parte di conteggio delta del tempo nella parte principale. Ho creato un sistema molto semplice come quello;

while(true) 
{ 
    long now = System.currentTimeMillis(); 

    if(!sessionPaused) 
    { 
     if(now-programLastMs>1000) 
     { 
      save(); 
      programLastMs = now; 
     } 
     sessionMs += now-sessionPrevMs; 
     overallMs += now-sessionPrevMs; 

     sessionPrevMs = now; 
     sessionLabel.setText(formatMillis("This Session:<br/>",sessionMs)); 
     overallLabel.setText(formatMillis("Overall:<br/>", overallMs)); 
    } 
} 

Questo codice ha causato un elevato utilizzo della CPU. Ho quindi sostituito questo blocco di codice con:

timer.scheduleAtFixedRate(new TimerTask() { 
      @Override 
      public void run() { 

       long now = System.currentTimeMillis(); 

       if(!sessionPaused) 
       { 
        if(now-programLastMs>1000) 
        { 
         save(); 
         programLastMs = now; 
        } 

        sessionMs += now-sessionPrevMs; 
        overallMs += now-sessionPrevMs; 

        sessionPrevMs = now; 

        sessionLabel.setText(formatMillis("This Session:<br/>",sessionMs)); 
        overallLabel.setText(formatMillis("Overall:<br/>", overallMs)); 
       } 
      } 
     }, 0, 1); 

E il problema era sparito. Mi chiedo solo la ragione. Inoltre, qual è il modo migliore per creare un ciclo del programma?

+3

Il ciclo 'while (true)' non fa alcuna pausa, quindi il ciclo è costantemente in esecuzione e mangia costantemente CPU. La pianificazione rende eseguibile il metodo 'run', solo quando è pianificato. – Berger

+0

Quindi, se avessi fatto in modo che lo schedulatore chiamasse una volta per 50 nanosecondi, sarebbe lo stesso?E ancora qual è il modo migliore per creare un loop di programma? @Berger – iGoodie

+0

Dipende dalla durata del metodo 'run', ma 50 nanosecondi sono veramente bassi, hai bisogno di una frequenza così alta? Comunque, come hai visto, è meglio lasciare respirare l'applicazione, quindi usa uno schedulatore o aggiungi un 'Thread.sleep' al tuo ciclo' while'. – Berger

risposta

5

Il primo blocco di codice funziona fondamentalmente alla velocità della CPU. Per capire questo, devi sapere cosa sono IPS e FLOPS. Una CPU moderna fa alcuni GFLOPS, il che significa che il tuo primo blocco viene eseguito decine o addirittura centinaia di migliaia di volte al secondo a seconda dell'hardware. Se lo esegui sul thread principale, bloccherà la tua interfaccia utente (ad esempio la tua interfaccia grafica rimarrà bloccata). Su un thread separato, verrà eseguito in modo continuo occupando risorse senza effettivamente fare molto.

Il secondo blocco, d'altra parte ha istruzioni specifiche da eseguire ogni millisecondo. Ciò significa che il tuo blocco di codice viene eseguito 1000 volte e il resto della CPU viene liberato per altri lavori.

Per rispondere alla domanda nel tuo commento: non è quasi mai accettabile utilizzare un ciclo infinito. I loop vengono utilizzati al meglio per una ripetizione limitata di un set di istruzioni. Nel tuo esempio, sembra che tu voglia chiamare il salvataggio ogni 1000 ms e anche contare il tempo di sessione. Vorrei

  1. separare il salvataggio su un timer ripetuto che viene chiamato ogni 1000ms.
  2. Creare un onSessionPause e onSessionResume che solo quando lo stato di pausa cambia. Ciò potrebbe essere dovuto a un pulsante di pausa o qualche altro tipo di condizione che si definisce. Le funzioni onSessionPause e onSessionResume dovrebbero essere in grado di registrare l'ora in cui vengono chiamate e aggiornare sessionM in base alla differenza di tempo.

A meno che non ti aspetti che le cose cambino ogni millisecondo, stai facendo in modo che la CPU lavori inutilmente.

+0

Questa era la risposta perfetta che stavo cercando. Grazie per le informazioni dettagliate (Y) – iGoodie

0

Inoltre, qual è il modo ottimale di creare un ciclo di programma?

Nel tuo caso specifico, il modo ottimale sarebbe un ciclo in esecuzione una volta al secondo, poiché questo raggiungerebbe il tuo obiettivo con un utilizzo minimo della CPU. Poiché ciò è impossibile da garantire, è necessario trovare una soglia sufficientemente bassa, in modo che il ciclo venga eseguito almeno una volta al secondo, e non troppo basso, per essere efficiente. Ti suggerirei di testare con qualche uscita.

Attenzione, codice diverso ha requisiti diversi, quindi non esiste un modo generale ottimale per eseguire il looping del codice. Come regola di base, dovresti cercare di evitare il maggior numero possibile di esecuzioni ridondanti.