2010-08-03 12 views
19

Mit dieser Warte Erklärung:Wie kann unterschieden werden, wenn wait (long timeout) für Notify oder Timeout beendet wird?

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

Es wird von InterruptedException verlassen könnte, oder durch Timeout oder weil dieser Artikel/notifyAll Methode in einem anderen Thread aufgerufen wurde, Ausnahme ist leicht zu fangen, aber ...

Es Gibt es eine Möglichkeit zu wissen, ob die Ursache der Ausfälle Timeout oder Notify war?

EDIT:

Dies ist eine schwierige Art und Weise, die funktionieren könnte (obwohl ich es nicht mögen)

  long tBefore=System.currentTimeMillis(); 
      wait(TIMEOUT); 
      if ((System.currentTimeMillis() - tBefore) > TIMEOUT) 
      { 
       //timeout 
      } 
+2

Ich hatte ein ähnliches Bedürfnis und in meinem Fall stellte sich heraus, dass ein 'Semaphore' besser geeignet war; 'Semaphore.tryAcquire (langes Timeout, TimeUnit-Einheit)' gibt 'false' zurück, wenn das Timeout abgelaufen ist. – Santosh

+0

Semaphore funktioniert nur, wenn Sie warten müssen, was nicht durch den öffentlichen Semaphore-Vertrag unterstützt wird. –

Antwort

7

Sie können nicht zwischen den beiden unterscheiden, wenn Sie einige zusätzliche bieten Code. Zum Beispiel durch ein ThreadLocalBoolean hinzufügen, die zu true gesetzt ist nur auf notify()

Aber zuerst müssen Sie sicherstellen, dass Ihre Logik erfordert diese Unterscheidung.

+4

Das OP wusste bereits, dass eine Ausnahme nicht ausgelöst wird und möchte zwischen einem Timeout und einem Notify unterscheiden. Dies liefert zu diesem Zweck keine nützlichen Informationen. –

+1

danke, ich habe das OP missverstanden. Jetzt aktualisiert – Bozho

+0

+1 für rewrite, und ja ein boolean und eine synchronisierte Methode ist, was ich jetzt –

1

Ausnahme wird nicht auf Benachrichtigung und Timeout ausgelöst.

Ich denke, es ist besser, sich auf java.lang.concurrent Paketsynchronisationsobjekte zu verlassen, statt Object.wait() zu verwenden.

12

Dies beantwortet die Frage nicht genau, aber es wird wahrscheinlich Ihr Problem lösen: Verwenden Sie höhere Gleichzeitigkeitsmechanismen. Wait/notify ist in der Regel niedriger als Sie wollen, aus diesem Grund unter vielen anderen.

Wenn Sie beispielsweise BlockingQueue.poll(long, TimeUnit) verwenden, können Sie überprüfen, ob das Ergebnis null ist, um zu wissen, ob das Zeitlimit überschritten wurde.

16

Es gibt noch einen weiteren Grund, warum notify zurückgeben kann: spurious wakeup. Dies ist eine unwahrscheinliche, aber mögliche Sache, weil das Verhindern von unerwünschten Wakeups bei einigen Hardware/Betriebssystem-Kombinationen sehr teuer ist.

Aus diesem Grund müssen Sie immer wait() in einer Schleife aufrufen und die Bedingung, auf die Sie warten, erneut prüfen. Während dieser Arbeit ist es einfach, gleichzeitig nach einem Timeout zu suchen.

Für Details empfehle ich das Buch "Java Concurrency in der Praxis". Und mit höheren Konstrukten, die das alles für Sie richtig machen.

+0

+1 Ich werde diese falschen Wecken haben –

2

Es gibt keine Möglichkeit, direkt zu sagen - das heißt, Sie müssten zusätzlichen Code hinzufügen, um dies zu bestimmen. Wenn Sie warten(), warten Sie oft darauf, dass etwas passiert, was den Zustand eines Objekts in irgendeiner Weise ändert - z. indem Sie vielleicht eine boolsche Variable setzen. Wenn dies der Fall ist, können Sie möglicherweise einfach den Status dieser Variablen überprüfen, um zu sehen, ob das Ereignis aufgetreten ist, oder Sie haben lediglich das Zeitlimit überschritten. Oder Sie können den Wert von System.currentTimeMillis() betrachten, um zu sehen, ob die verstrichene Zeit größer oder gleich der Timeout-Zeit ist. Wenn dies der Fall ist, haben Sie wahrscheinlich eine Zeitüberschreitung (obwohl dies keine absolute Garantie ist)). Oder wenn die verstrichene Zeit kürzer ist als die Zeitüberschreitung, haben Sie mit Sicherheit keine Zeitüberschreitung. Hilft das?

+0

Ich benutze tatsächlich currentTimeMillis(), aber ich frage mich, ob es etwas besseren Weg war –

+0

@ Hernán Eche Wie ich in meiner Antwort habe es nicht eine absolute Garantie. Wenn Sie wissen, warum Sie feststellen möchten, ob es zeitlich begrenzt ist? Wir können nach einer Lösung suchen. – YoK

+0

Ja, ich weiß, das ist kein sehr guter Ansatz, ich benutze es für eine Schleife while (true) {wait (timeout); andere Aufgaben..; } so kann es die Schleife beenden, wenn die Wartezeit wirklich mitgeteilt wurde, zum Beispiel, wenn Wartezeit boolean zurückkommen würde, wäre es etwas wie while (wahr) {if (warte (Zeitüberschreitung)) break; andere Aufgaben..; } Ich kapsle alles innerhalb einer Klasse und ein Flag mit synchronisierter Methode, um parallel zur Einstellung dieses Flags zu warten/zu benachrichtigen –

3

Verwenden Sie nicht System.currentTimeMillis(), verwenden Sie stattdessen System.nanoTime().

Die erste misst die absolute Zeit (basierend auf der Systemuhr) und kann seltsame Ergebnisse haben, wenn die Systemzeit geändert wird. Zum Beispiel: Eine Wartezeit von 5 Sekunden kann eine Stunde dauern, wenn die Uhr um eine Stunde rückwärts bewegt wird, oder eine Wartezeit von 10 Minuten wird nach 0 Sekunden ausgeführt, wenn die Uhr vorwärts bewegt wird.

Der zweite misst die relative Zeit. Es läuft immer in einer Richtung mit konstanter Geschwindigkeit, , aber es hat keinen Ursprung. Das bedeutet, dass die Werte nur zur Messung der relativen Zeit verwendet werden können, aber nicht zur Bestimmung eines Datums verwendet werden können und sollten.