Pregunta

Estoy tratando de poner en práctica Future.get (largo, TimeUnit) en términos de TimeUnit.timedWait (Object, long) .

No está claro cómo utilizar TimeUnit.timedWait(Object, long) de manera que se encarga de activaciones falsas sin perder el componente de nanosegundo TimeUnit. Lo normal sería hacer algo como esto:

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);
  }
}

pero se pierde el componente nanosegundo. Si todo el mundo está más que soltar el componente nanosegundo entonces ¿cuál es el punto de TimeUnit incluso nanosegundos de apoyo y oferta TimeUnit.timedWait()?

¿Fue útil?

Solución 3

CountDownLatch parece ser la forma más fácil de poner en práctica lo siguiente:

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 no es vulnerable a espuria wakeups (porque puede comprobar el estado de cierre internamente antes de regresar).

Otros consejos

Antes de esperar, memorizar la hora a la que desea tiempo de espera.

Antes de que notifique a la rosca de espera, establecer algún compartida (sincronizada) de señalización del estado de que el hilo de espera debe dejar de esperar porque el cálculo se ha completado.

Cuando el hilo se despierta de la espera por cualquier razón se debe comprobar el estado compartido para ver si debe dejar de esperar, y también debe comprobar cuánto tiempo queda antes de que expire el tiempo de espera. Si el tiempo de espera no ha expirado, y el estado compartido dice no dice que dejar de esperar entonces usted debe esperar de nuevo (pero usando un nuevo tiempo más corto a cabo calcula a partir de la hora actual).

La respuesta a sus mentiras pregunta en el Object.wait (largo) spec:

Un hilo también puede despertar sin haber sido notificada, interrumpida, o el tiempo de espera, una llamada de activación espuria. Aunque esto va a ocurrir raramente en la práctica, las solicitudes deben protegerse contra ella mediante pruebas de la condición que debe haber causado el hilo a ser despertado, y continuando a esperar si la condición no se cumple. En otras palabras, espera siempre deben ocurrir en bucles, como éste:

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

(Para obtener más información sobre este tema, véase la Sección 3.2.3 en "Programación Concurrente en Java (Segunda Edición)" de Doug Lea (Addison-Wesley, 2000), o el artículo 50 en Joshua Bloch "Effective Java Programming Guide Idioma" (Addison-Wesley, 2001).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top