web-dev-qa-db-fra.com

Comment différencier quand attendre (long délai) quitter pour notify ou timeout?

Avoir cette déclaration d'attente:

public final native void wait(long timeout) throws InterruptedException;

Il peut sortir par InterruptedException, ou par timeout, ou parce que la méthode Notify/NotifyAll a été appelée dans un autre thread, Exception est facile à détecter mais ...

Il y a un moyen de savoir si la cause des sorties était timeout ou notify?

MODIFIER:

C'est un moyen délicat qui pourrait fonctionner (même si je ne l'aime pas)

          long tBefore=System.currentTimeMillis();
          wait(TIMEOUT);
          if ((System.currentTimeMillis() - tBefore) > TIMEOUT) 
            { 
               //timeout
            }
25
Hernán Eche

Vous ne pouvez pas différencier les deux à moins de fournir du code supplémentaire. Par exemple, en ajoutant une ThreadLocalBoolean qui est définie sur true uniquement sur notify()

Mais vous devez d’abord vous assurer que votre logique exige cette différenciation.

10
Bozho

Il y a une autre raison pour laquelle notify peut revenir: un réveil fallacieux. C'est une chose improbable mais possible, car la prévention des réveils parasites est très coûteuse pour certaines combinaisons matériel/système d'exploitation.

Pour cette raison, vous devez toujours appeler wait () dans une boucle et revérifier la condition que vous attendez. Pendant ce travail, il est facile de vérifier le délai d’expiration en même temps.

Pour plus de détails, je recommande le livre "Java Concurrency In Practice". Et en utilisant des constructions de plus haut niveau pour que tout soit correct pour vous.

16
Darron

Cela ne répond pas exactement à la question, mais cela résoudra probablement votre problème: utilisez des mécanismes de simultanéité de niveau supérieur. Attendre/notifier est généralement plus faible que vous ne le souhaiteriez, pour cette raison parmi tant d'autres.

Par exemple, si vous utilisiez BlockingQueue.poll(long, TimeUnit) , vous pouvez vérifier si le résultat est null pour savoir si votre délai a expiré.

12
Mark Peters

N'utilisez pas System.currentTimeMillis(), utilisez plutôt System.nanoTime()

Le premier mesure le temps absolu (basé sur l’horloge du système) et peut donner des résultats curieux si l’heure du système est modifiée. Par exemple: une attente de 5 secondes peut durer une heure si l’horloge est décalée d’une heure en arrière, ou une attente de 10 minutes sera exécutée après 0 seconde si l’horloge est déplacée vers l’avant.

La seconde mesure le temps relatif. Il fonctionnera toujours dans un sens à vitesse constante, mais il n’a pas d’origine . Cela signifie que les valeurs ne peuvent être utilisées que pour mesurer le temps relatif, mais ne peuvent et ne doivent pas être utilisées pour déterminer une date.

3
tobain

Il n'y a aucun moyen de dire directement - c'est-à-dire qu'il vous faudrait ajouter du code supplémentaire pour le déterminer. Souvent, lorsque vous attendez (), vous attendez quelque chose qui change l’état d’un objet d’une manière ou d’une autre - par exemple, en définissant une variable booléenne, peut-être. Si tel est le cas, vous pourrez simplement vérifier l'état de cette variable pour voir si l'événement s'est produit ou vous avez simplement dépassé le délai imparti. Ou vous pouvez regarder la valeur de System.currentTimeMillis () pour voir si le temps écoulé est supérieur ou égal au délai d'attente. Si c'est le cas, il s'agirait d'un indice que vous avez probablement dépassé le délai (mais ce n'est pas une garantie absolue ). Ou si le temps écoulé est inférieur au délai d'attente, vous n'avez certainement pas dépassé le délai imparti. Est ce que ça aide?

2
YoK

L'exception n'est pas lancée sur notify et time out.

Je pense qu'il est préférable de s'appuyer sur les objets de synchronisation de paquets Java.lang.concurrent au lieu d'utiliser Object.wait().

1
Manuel Selva

Vous devez utiliser l'approche pas attendre/notifier.

Sera préférable d’utiliser Lock with Condidions https://docs.Oracle.com/javase/8/docs/api/Java/util/concurrent/locks/Condition.html#await-long-Java.util.concurrent. TimeUnit-

Il a attendu avec timeout et retournera false si le temps d'attente s'est écoulé de manière détectable avant le retour de la méthode, sinon true

0
Aleksandr Filichkin