Exécuter du code pendant x secondes en Java?

Je voudrais écrire une boucle java while qui va itérer pendant 15 secondes. Une façon de le faire serait de stocker l'heure système actuelle + 15sec, puis de la comparer à l'heure actuelle dans la signature de la boucle while.

Est-il un meilleur moyen?

23
demandé sur Mat 2010-01-08 19:46:30

12 réponses

La conception de ceci dépend de ce que vous voulez faire pendant 15s. les deux cas les plus plausibles sont "faites ceci tous les X pendant 15s" ou "attendez que X arrive ou 15s celui qui arrive plus tôt", ce qui conduira à un code très différent.

Juste en attente

Fil de discussion.dors(15000)

Cela n'itère pas, mais si vous voulez ne rien faire pendant 15s, c'est beaucoup plus efficace (cela gaspille moins de CPU en ne faisant rien).

Répétez un peu de code pour 15s

Si vous voulez vraiment faire une boucle pour 15s alors votre solution est bonne, tant que votre code ne prend pas trop de temps. Quelque chose comme:

long t= System.currentTimeMillis();
long end = t+15000;
while(System.currentTimeMillis() < end) {
  // do something
  // pause to avoid churning
  Thread.sleep( xxx );
}

Attendez 15s ou une autre condition

Si vous voulez que votre code soit interrompu après exactement 15 secondes, vous aurez besoin d'une solution multithread. Regardez java.util.concurrent pour beaucoup d'objets utiles. La plupart des méthodes qui se verrouillent (comme wait ()) ont un argument timeout. Un sémaphore {[7] } peut faire exactement ce dont vous avez besoin.

51
répondu Nick Fortescue 2014-04-04 23:41:09

Comme déjà mentionné par d'autres affiches, si vous voulez juste que le fil s'arrête pendant un certain temps, Utilisez Thread.sleep().

Si vous voulez que le thread fasse quelque chose, mais que vous voulez le faire arrêter après un certain temps, utilisez quelque chose comme:

class Foo implements Runnable {
    private volatile boolean killed = false;

    public void run() {
        while (!killed) {
            try { doOnce(); } catch (InterruptedException ex) { killed = true; }
        }
    }

    public void kill() { killed = true; }
    private void doOnce() throws InterruptedException { /* .. */ }
}

Et à partir du thread principal, faites:

Foo foo = new Foo(); 
Thread thread = new Thread(foo);
thread.start();

/* when you want to stop it */
foo.kill();
thread.interrupt();
4
répondu Binil Thomas 2010-01-09 19:03:15

Essayez ceci:

public class SleepMessages {
    public static void main(String args[]) throws InterruptedException {
        String importantInfo[] = {
            "Mares eat oats",
            "Does eat oats",
            "Little lambs eat ivy",
            "A kid will eat ivy too"
        };

        for (int i = 0; i < importantInfo.length; i++) {
            //Pause for 15 seconds
            Thread.sleep(15000);
            //Print a message
            System.out.println(importantInfo[i]);
        }
    }
}

Plus d'infos : ici

3
répondu Michel Gokan 2010-01-08 16:54:56

Votre approche générale semble bien bien que vous souhaitiez voir si l'heure actuelle est supérieure au point que vous voulez arrêter, sinon vous risquez de courir longtemps.

L'alternative est d'exécuter une minuterie / thread qui définit un indicateur après 15 secondes se sont écoulées. Cet indicateur devrait être marqué comme volatile sinon votre boucle pourrait ne pas voir le changement se produire dans la valeur.

Le choix si vous vous souciez de l'efficacité est ce qui est plus cher, obtenir le temps du système une fois par boucle ou accéder à une variable volatile? Je ne sais pas lequel est le plus efficace - vous pouvez le comparer si c'est vraiment important.

Pour un code simple et maintenable, je choisirais l'approche de vérification de la minuterie:

long endTime = System.currentTimeMillis() + 15000
while (System.currentTimeMillis() < endTime) {
  //loop
} 
2
répondu Robert Christie 2010-01-08 17:03:07

Vous pouvez utiliser AOP et a @Timeable annotation de jcabi-aspects (je suis un développeur):

@Timeable(limit = 1, unit = TimeUnit.SECONDS)
String load(String resource) {
  // do this check regularly:
  if (Thread.currentThread.isInterrupted()) {
    throw new IllegalStateException("time out");
  }
  // execution as normal
}

Lorsque la limite de temps est atteinte, votre thread obtiendra interrupted() flag défini sur true et c'est votre travail de gérer cette situation correctement et d'arrêter l'exécution.

1
répondu yegor256 2013-04-05 18:02:40

En supposant que vous voulez que la boucle fasse quelque chose de sensé, vous pourriez trouver plus rapide de vérifier un drapeau volatile. Demandez à un autre thread d'attendre 15 secondes (ou utilisez une minuterie), puis réglez-le.

Alternativement, si vous savez à peu près combien de temps le corps de la boucle prendra, exécutez - le quelques centaines de fois, disons, et faites le contrôle du temps dans une boucle externe.

final long start = System.nanoTime();
do {
    for (int i=0; i<200, ++i) {
        ...
    }
} while (System.nanoTime()-start < 15L*1000L*1000L*1000L);

System.nanoTime ne devrait pas être confondu par les changements d'horloge système. L'utilisation de nombres littéraux longs est importante.

0
répondu Tom Hawtin - tackline 2010-01-08 16:53:32

Vous pourriez être intéressé par la planification D'une TimerTask qui arrête un autre thread ou modifie l'état de votre boucle.

0
répondu YuppieNetworking 2010-01-08 16:53:57

Ne vérifiez jamais l'heure actuelle dans une boucle serrée.

Sinon, quelqu'un avec un ordinateur portable peut se faire brûler ses genoux par un processeur surchauffé. J'ai entendu les histoires de ce qui se passe réellement.

0
répondu Alexander Pogrebnyak 2010-01-08 16:58:38

Pour le java.util.approche concurrente , Voir Chapitre 6 de la concurrence Java dans la pratique (section 6.3.7 fixer des limites de temps sur les tâches, page 131).

Exemple de Code: extraction d'une publicité avec un budget de temps.

0
répondu Steven G. Brown 2010-01-08 18:49:35

Une solution similaire à @Tom Hawtin Sans Taille de boucle arbitraire.

final long end = System.nanoTime() + 15 * 1000 * 1000 * 1000L;
int loop = 1;
do {
    for (int i=0; i<loop; ++i) {
        ...
    }
    loop++;
} while (System.nanoTime() < end);

Dans ce cas, la taille de la boucle interne commencera petite mais augmentera si la boucle est particulièrement rapide. S'il est assez lent, il ne peut itérer qu'une seule fois.

0
répondu Peter Lawrey 2010-01-09 13:36:41

Voici ma suggestion et ça marche bien pour moi:)

StoppingTime = 15 ;
int loop = 1;
long StartTime = System.currentTimeMillis() / 1000 ;
for (int i=0; i<loop; ++i) {
    // your code here

    loop++;
    if (((System.currentTimeMillis()/1000) - StartTime) > StoppingTime)
        loop=0;
}
0
répondu Ghassen Bellagha 2013-09-03 16:09:26

Je vous suggère de le faire avec la classe timer en évitant le Fil.sommeil (xxx); méthode.

Par exemple:

import java.util.Timer;
import java.util.TimerTask;

public class TimerExample {
    private int globalTimer = 0;
    private int limitTimer = 15;

    public static void main(String[] args) {
        new TimerExample();
    }

    public TimerExample() {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                globalTimer++;
                // DO YOUR CODE HERE
                System.out.println("running");
                if (globalTimer == limitTimer) {
                    timer.cancel();
                }
            }
        }, 0, 1000);
    }
}
0
répondu theo231022 2017-12-08 22:03:42