Wie zu verwenden TimeUnit.timedWait() ohne Verlust einer Genauigkeit im Nanosekundenbereich?

StackOverflow https://stackoverflow.com/questions/1975620

  •  21-09-2019
  •  | 
  •  

Frage

Ich bin versucht zu implementieren Zukunft.get(long, TimeUnit) in Bezug auf die TimeUnit.timedWait(Object, long).

Es ist nicht klar, wie zu verwenden TimeUnit.timedWait(Object, long) in einer Weise, dass die Griffe spurious wakeups, ohne die Nanosekunden-Komponente von TimeUnit.Normalerweise würde man so etwas wie dies tun:

public V get(long timeout, TimeUnit unit)
{
  long expirationTime = new Date().getTime() + unit.toMillis(timeout);
  while (!condition)
  {
    long timeLeft = expirationTime - new Date().getTime();
    if (timeLeft <= 0)
      throw new TimeoutException();
    unit.timedWait(object, timeLeft);
  }
}

aber Sie verlieren die Nanosekunden-Komponenten.Wenn jeder einfach fallenlassen der Nanosekunden-Komponente, was ist der Punkt von TimeUnit auch die Unterstützung von Nanosekunden und Angebot TimeUnit.timedWait()?

War es hilfreich?

Lösung 3

CountDownLatch scheint der einfachste Weg, dies zu implementieren:

public class MutableFuture<T> implements Future<T>
{
  private final CountDownLatch done = new CountDownLatch(1);
  private T value;
  private Throwable throwable;

  public synchronized boolean isDone()
  {
    return done.getCount() == 0;
  }

  public synchronized T get(long timeout, TimeUnit unit)
    throws InterruptedException, ExecutionException, TimeoutException
  {
    if (!done.await(timeout, unit))
      throw new TimeoutException();
    if (throwable != null)
      throw new ExecutionException(throwable);
    return value;
  }

  // remaining methods left as exercise to the reader :)
}

CountdownLatch ist nicht anfällig für unechten Wakeups (weil es den Verriegelungszustand intern überprüft vor der Rückkehr).

Andere Tipps

Bevor Sie warten, speichern Sie die Zeit ein, in der ein timeout Auftritt.

Bevor Sie Benachrichtigen, der wartende thread, set some shared (synchronized) Zustand signalisiert, dass der wartende thread sollte nicht mehr warten, weil die Berechnung abgeschlossen ist.

Wenn der thread aufwacht, aus der warte für was auch immer Grund, es sollten überprüfen, den gemeinsamen Staat zu sehen, ob Sie aufhören sollte, zu warten, und es sollte auch überprüfen, wie lange übrig ist, bevor das Zeitlimit abläuft.Wenn das Zeitlimit noch nicht abgelaufen ist, und den gemeinsamen Status sagt nicht sagen, zu stoppen warten, dann sollten Sie warten, wieder (aber mit einem neuen kürzeren Zeit, in der sich berechnet aus dem aktuellen Zeit).

Die Antwort auf Ihre Frage liegt in der Object.wait (long) spec:

Ein Thread kann auch, ohne aufwachen werden benachrichtigt, unterbrochen oder Zeitüberschreitung, eine so genannte unechte Wakeup. Während dies in der Praxis selten auftritt, Anwendungen müssen dagegen wappnen, indem er für den Zustand zu testen, dass der Faden geweckt wird verursacht haben sollte, und wenn die Bedingung erfüllt ist, nicht zu warten fort. Mit anderen Worten, sollte wartet treten immer in Schleifen, wie diese:

 synchronized (obj) {
     while (<condition does not hold>)
         obj.wait(timeout);
     ... // Perform action appropriate to condition
 }

(Weitere Informationen zu diesem Thema finden Sie in Abschnitt 3.2.3 in Doug Lea "Concurrent Programming in Java (Second Edition)" (Addison-Wesley, 2000), oder Artikel 50 in Joshua Blochs "Effective Java Programming Language Guide" (Addison-Wesley, 2001).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top