169 votes

Comment définir une minuterie en Java ?

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

1 votes

L'OP pourrait-il préciser s'il souhaite simplement tenter l'action pendant au moins 2 minutes, ou si l'exception doit être levée après les deux minutes, même si une tentative de connexion est en cours ?

301voto

andrewmu Points 6436

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

Réglage d'une minuterie

Tout d'abord, vous devez créer un Timer (j'utilise la fonction java.util version ici) :

import java.util.Timer;

..

Timer timer = new Timer();

Pour exécuter la tâche une fois, vous devez faire ce qui suit

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 en sorte que le délai d'une tâche soit dépassé

Pour faire spécifiquement ce que la question clarifiée demande, c'est-à-dire tenter d'effectuer une tâche pendant une période donnée, vous pourriez faire ce qui 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, l'exception TimeoutException sera lancée.

Un problème est que même si vous obtenez une TimeoutException après les deux minutes, la tâche continuera réellement à s'exécuter Il est probable qu'une connexion à une base de données ou à un réseau finira par s'interrompre et déclencher une exception dans le fil de discussion. Mais sachez que cela peut consommer des ressources jusqu'à ce que cela se produise.

0 votes

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

0 votes

Je suis désolé mais mon exigence est que je veux donner 2 minutes pour se connecter à la base de données et ensuite il va juste jeter un message d'erreur.

8 votes

ATTENTION AUX LECTEURS : Cette réponse est manifestement fausse. Il définit une minuterie pour attendre 2 minutes, puis exécute une requête DB après ce délai de 2 minutes, et l'exécute encore et encore toutes les 2 minutes. Ce qu'elle ne fait PAS, c'est d'exécuter la requête DB tout de suite, puis d'échouer après 2 minutes, ce qui est, je pense, ce que la question demandait (comme précisé dans le commentaire).

26voto

nimWM Points 63

Utilisez cette

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 votes

Hmm... cela pourrait techniquement fonctionner, sauf que cela ne couvre pas les cas limites, où le temps s'écoule pendant que vous effectuez un sondage de la base de données, ce qui peut être requis par le PO.

1 votes

C'est la seule réponse correcte. 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 par le nombre d'exemples sur StackOverflow qui suggèrent le même genre d'erreur.

1 votes

@thecoshman - Les implémentations de minuterie n'interrompent PAS l'opération DB une fois qu'elle est en cours, et ceci n'est pas le cas. Dans tous les cas, vous ne pouvez contrôler que l'heure à laquelle vous démarrez l'opération DB. On pense souvent, à tort, qu'il faut une "minuterie" pour chronométrer les choses, mais ce n'est pas le cas. Il suffit de FAIRE quelque chose et, en utilisant l'heure actuelle, de s'assurer que vous ne le fassiez pas trop longtemps.

12voto

andrewmu Points 6436

Ok, je pense que je comprends votre problème maintenant. Vous pouvez utiliser un Future pour essayer de faire quelque chose, puis attendre un peu 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
}

0 votes

L'exception est levée mais le programme ne se termine pas. Veuillez m'aider.

2 votes

Vous pouvez utiliser la classe ExecutorService au lieu de l'Executor. Elle possède la méthode shutdown() pour arrêter l'exécuteur.

1 votes

Les exécuteurs avalent les exceptions lancées que vous ne traitez 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 plutôt que de la posséder, vous devez alors sous-classer le ScheduledExecutorService et surcharger afterExecute (assurez-vous d'appeler super.afterExecute()). Le second argument de afterExecute sera le throwable du Runnable/Callable.

7voto

Comment arrêter le minuteur ? Arrêtez et jouez à nouveau lorsque vous faites quelque chose dans ce code.

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

Lorsque j'utilise le timer.cancel();

il s'arrêtera mais si on ferme le formulaire et qu'on l'ouvre à nouveau, le problème sera résolu.

Exception
Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Timer already cancelled.
    at java.util.Timer.sched(Timer.java:354)
    at java.util.Timer.scheduleAtFixedRate(Timer.java:296)
    at View.Electronic_Meeting.this_componentShown(Electronic_Meeting.java:295)
    at View.Electronic_Meeting.access$000(Electronic_Meeting.java:36)
    at View.Electronic_Meeting$1.componentShown(Electronic_Meeting.java:85)
    at java.awt.AWTEventMulticaster.componentShown(AWTEventMulticaster.java:162)
    at java.awt.Component.processComponentEvent(Component.java:6095)
    at java.awt.Component.processEvent(Component.java:6043)
    at java.awt.Container.processEvent(Container.java:2041)
    at java.awt.Component.dispatchEventImpl(Component.java:4630)
    at java.awt.Container.dispatchEventImpl(Container.java:2099)
    at java.awt.Component.dispatchEvent(Component.java:4460)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

4voto

Mahadev Mane Points 620
    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);

0 votes

Copiez simplement le code ci-dessus, il fonctionnera parfaitement. J'ai donné deux temps 'time', le premier est pour la première fois pour exécuter ce code et le second est pour le temps d'intervalle.

2 votes

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X