Comment définir une minuterie en Java?


151

Comment définir une minuterie, par exemple pendant 2 minutes, pour essayer de se connecter à une base de données, puis lever une exception en cas de problème de connexion?


1
Coul l'OP clarifier s'ils souhaitent simplement tenter l'action pendant au moins 2 minutes, ou si l'exception doit être lancée maintenant plus tard dans les deux minutes, même si une tentative de connexion est actuellement en cours
thecoshman

Réponses:


280

Donc, la première partie de la réponse est de savoir comment faire ce que le sujet demande, car c'est ainsi que je l'ai initialement interprété et quelques personnes ont semblé trouver utile. La question a été clarifiée depuis et j'ai élargi la réponse pour y répondre.

Réglage d'une minuterie

Vous devez d'abord créer un minuteur (j'utilise la java.utilversion ici):

import java.util.Timer;

..

Timer timer = new Timer();

Pour exécuter la tâche une fois que vous le feriez:

timer.schedule(new TimerTask() {
  @Override
  public void run() {
    // Your database code here
  }
}, 2*60*1000);
// Since Java-8
timer.schedule(() -> /* your database code here */, 2*60*1000);

Pour que la tâche se répète après la durée que vous feriez:

timer.scheduleAtFixedRate(new TimerTask() {
  @Override
  public void run() {
    // Your database code here
  }
}, 2*60*1000, 2*60*1000);

// Since Java-8
timer.scheduleAtFixedRate(() -> /* your database code here */, 2*60*1000, 2*60*1000);

Faire une tâche timeout

Pour faire spécifiquement ce que demande la question clarifiée, c'est-à-dire tenter d'exécuter une tâche pendant une période donnée, vous pouvez procéder comme suit:

ExecutorService service = Executors.newSingleThreadExecutor();

try {
    Runnable r = new Runnable() {
        @Override
        public void run() {
            // Database task
        }
    };

    Future<?> f = service.submit(r);

    f.get(2, TimeUnit.MINUTES);     // attempt the task for two minutes
}
catch (final InterruptedException e) {
    // The thread was interrupted during sleep, wait or join
}
catch (final TimeoutException e) {
    // Took too long!
}
catch (final ExecutionException e) {
    // An exception from within the Runnable task
}
finally {
    service.shutdown();
}

Cela s'exécutera normalement avec des exceptions si la tâche se termine dans les 2 minutes. Si elle s'exécute plus longtemps que cela, TimeoutException sera levée.

Un problème est que bien que vous obteniez une TimeoutException après les deux minutes, la tâche continuera en fait à s'exécuter , bien que vraisemblablement une base de données ou une connexion réseau finira par expirer et lèvera une exception dans le thread. Mais sachez que cela pourrait consommer des ressources jusqu'à ce que cela se produise.


Oh, je suppose que vous avez mal compris mon problème, je dois essayer à plusieurs reprises de me connecter à la base de données jusqu'à 2 minutes à chaque fois
Ankita

Je suis désolé mais mon exigence est que je veuille donner 2 minutes pour me connecter à la base de données, puis cela lancera juste un message d'erreur.C'est comme si je voulais définir une limite de temps pour essayer de me connecter à la base de données
Ankita

7
ATTENTION AUX LECTEURS: Cette réponse est manifestement erronée. Il définit un minuteur pour attendre 2 minutes, puis exécuter une requête de base de données après ce délai de 2 minutes, puis il l'exécute encore et encore toutes les 2 minutes. Ce qu'il ne fait PAS, c'est d'exécuter la requête DB tout de suite, puis d'échouer après 2 minutes, ce que je pense que la question a demandé (comme précisé dans le commentaire).
AgilePro

2
@AgilePro C'était vrai. Je n'ai pas répondu à la question car elle a finalement été posée et je l'ai maintenant mise à jour pour y répondre.
andrewmu

1
@ErnestasGruodis Les API principales répertorient le constructeur comme public: docs.oracle.com/javase/7/docs/api/java/util/Timer.html#Timer () Vous pouvez avoir une classe Timer différente dans votre chemin de classe - essayez java. util.Timer comme classe.
andrewmu

25

Utilisez ceci

long startTime = System.currentTimeMillis();
long elapsedTime = 0L.

while (elapsedTime < 2*60*1000) {
    //perform db poll/check
    elapsedTime = (new Date()).getTime() - startTime;
}

//Throw your exception

1
hmm ... cela fonctionnerait techniquement, sauf que cela ne couvre pas les cas
marginaux

1
C'est la seule bonne réponse. Il fonctionnera sur un seul thread et calculera l'heure de fin sans dérive. Utiliser une TimerTask est exactement la mauvaise chose à faire dans ce cas. Je suis surpris de voir combien d'exemples sur StackOverflow suggèrent ce même genre de chose qui ne va pas.
AgilePro du

1
@thecoshman - les implémentations de temporisateur n'interrompent PAS l'opération DB une fois qu'elle est en cours, ni cela. Dans tous les cas, vous ne pouvez contrôler que l'heure à laquelle vous démarrez l'opération DB. Il y a une idée fausse courante selon laquelle vous avez besoin d'un «minuteur» pour chronométrer les choses, mais ce n'est pas le cas. Vous n'avez qu'à FAIRE quelque chose, et en utilisant l'heure actuelle, assurez-vous de ne pas le FAIRE trop longtemps.
AgilePro

disons que vous devez soit retourner la connexion ou jeter après EXACTEMENT deux minutes, cela ne fonctionnera pas. ce sera le cas si APRÈS deux minutes de tentative de connexion, vous ne parvenez toujours pas à vous connecter. Dans une situation où la vérification de la connexion prend par exemple deux semaines, cela prendra autant de temps pour lever une exception.
thecoshman

14
C'est en fait un très mauvais style de codage, car la boucle while s'exécute constamment et vérifie les trucs ... mauvais pour le processeur et mauvais pour la durée de vie de la batterie.
Infinite

11

Ok, je pense que je comprends votre problème maintenant. Vous pouvez utiliser un Future pour essayer de faire quelque chose, puis expirer au bout d'un moment si rien ne s'est passé.

Par exemple:

FutureTask<Void> task = new FutureTask<Void>(new Callable<Void>() {
  @Override
  public Void call() throws Exception {
    // Do DB stuff
    return null;
  }
});

Executor executor = Executors.newSingleThreadScheduledExecutor();
executor.execute(task);

try {
  task.get(5, TimeUnit.SECONDS);
}
catch(Exception ex) {
  // Handle your exception
}

Une exception est levée mais le programme ne se termine pas. Veuillez m'aider à résoudre ce problème.
Ankita

2
Vous pouvez utiliser la classe ExecutorService au lieu de Executor. Il a la méthode shutdown () pour arrêter l'exécuteur.
Rites

1
Les exécuteurs avalent les exceptions lancées que vous ne gérez pas spécifiquement dans votre Callable / Runnable. Si votre Runnable / Callable n'attrape pas et ne gère pas l'exception elle-même et qu'elle vous est fournie par rapport à vous en êtes propriétaire, vous devez sous-classer ScheduledExecutorService et remplacer afterExecute (assurez-vous d'appeler super.afterExecute ()). Le deuxième argument de afterExecute sera le jetable de Runnable / Callable
adam

3
    new java.util.Timer().schedule(new TimerTask(){
        @Override
        public void run() {
            System.out.println("Executed...");
           //your code here 
           //1000*5=5000 mlsec. i.e. 5 seconds. u can change accordngly 
        }
    },1000*5,1000*5); 

copiez simplement le pest au-dessus du code, cela fonctionnera bien. J'ai donné deux fois le «temps», le premier est pour la première fois pour exécuter ce code et le second est pour le temps d'intervalle.
Mahadev Mane

La documentation de Timer recommande d'utiliser le framework Executor à la place. docs.oracle.com/javase/10/docs/api/java/util/Timer.html
Karan Khanna

1

[Android] si quelqu'un cherche à implémenter un minuteur sur Android en utilisant java .

vous devez utiliser un fil d'interface utilisateur comme celui-ci pour effectuer des opérations.

Timer timer = new Timer();
timer.schedule(new TimerTask() {
           @Override
            public void run() {
                ActivityName.this.runOnUiThread(new Runnable(){
                    @Override
                      public void run() {
                       // do something
                      }        
                });
            }
        }, 2000));
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.