Pregunta

He implementado un sistema de tokens que asigna un número fijo de tokens. Cada token en la asignación inicia un temporizador que caduca después de unos pocos minutos y borra esa ranura de token para su reutilización. Si el usuario valida el token antes de que expire el temporizador, se supone que el Timer se debe cancelar y restablecer con otro período de validez del token. Parece que no puedo cancelar el temporizador desde fuera del subproceso del temporizador, se espera este comportamiento. Siguen los fragmentos:

/**
 * Fills one of the available slots with a new session key
 * @param sessionKey
 * @return true on slot fill success - false on fail
 */
public boolean fillSlot(String sessionKey)
{
    if(count<MAXCOUNT)
    {
        //Add key to slot
        slots.add(sessionKey);
        //Up the key count
        upCount();
        //Set up expiry timer
        Timer timer = new Timer();
        timer.schedule(new ExpiringTokentask(timer,sessionKey), EXPIRY_TIME);
        timers.put(sessionKey, timer);
        return true;
    }
    return false;
}

    /**
 * Check if a given key is stored in the slots
 * reset timer every time key is checked
 * @param sessionKey
 * @return true on key found false on not found
 */
public boolean checkSlot(String sessionKey)
{
    //TODO: More efficient key search and storage for larger user sets
    //TODO: Upgrade from memory array to h2 embedded DB
    for(int i=0;i<slots.size();i++)
    {
        if(sessionKey.equals(slots.get(i)))
        {
            //Reset timer
            Timer timer = timers.get(sessionKey);
            //Can't seem to do this
            // timer.cancel();
            timer.schedule(new ExpiringTokentask(timer,sessionKey), EXPIRY_TIME);
            //Return token validation
            return true;
        }
    }

    return false;
}


private class ExpiringTokentask extends TimerTask
{
    private Timer timer;
    private String expireToken;

    public ExpiringTokentask(Timer timer, String sessionKey)
    {
        this.timer = timer;
        this.expireToken = sessionKey;
        System.out.println(sessionKey);
    }

    public void run() {
        System.out.format("Time's up!%n");
        clearSlot(expireToken);
        timer.cancel(); //Terminate the timer thread
    }
}
¿Fue útil?

Solución

Como se dijo, puede cancelar la Tarea de Temporizador que se envió al temporizador en lugar de cancelar el temporizador, de esta manera no tendrá que agregar más temporizadores.

Lo que estás haciendo:

timer.cancel();
timer.schedule(...);

lanzará IllegalStateExceptions ya que NO PUEDES programar nuevas tareas en un temporizador cancelado.

Así que en lugar de hacerlo: timer.cancel () haga que su mapa sea una asignación de claves de sesión a TimerTasks y cancele TimerTask en lugar de TimerTask. De esta manera, no tiene que renovar los nuevos temporizadores y su temporizador funcionará como se esperaba después de cancelar una o más de sus tareas. También podrá utilizar un temporizador para manejar muchas sesiones. Ahora mismo estás creando un temporizador y, por lo tanto, un hilo por sesión.

En otra nota, NO debes usar java.util.Timer . ¿Qué sucede si cualquiera de sus TimerTasks lanza una excepción? ¡Tu Temporizador será asesinado y nunca volverá a correr! ¿Qué sucede si una de sus Tareas de Timer es lenta o se bloquea por un período indefinido? Cualquier otra Tareas de Timer en ese temporizador no podrá ejecutarse. Busque en el uso de un ScheduledThreadPoolExecutor en su lugar. Estoy seguro de que java.util.Timer quedará en desuso en la próxima versión de Java.

Otros consejos

Creo que puedes usar un solo objeto de temporizador y crear tantas Tareas de Timer en lugar de crear muchos temporizadores. Los temporizadores son costosos, por lo que el uso de uno o dos temporizadores para toda la aplicación debería ser suficiente. Además, está cancelando el temporizador y no TimerTask intente cancelar la TimerTask

Si el temporizador no es nulo, deberías poder llamar a cancel () desde cualquier hilo. Una mejor manera de hacerlo es utilizar un ScheduledExecutorService , y obtener un Future para cada tarea enviada. Con el futuro, puede cancelarlo o verificar el resultado.

Después de la línea donde intenta cancelar el temporizador, debe crear uno nuevo antes de llamar al método de programación.

if(sessionKey.equals(slots.get(i)))
{
  //Reset timer
  Timer timer = timers.get(sessionKey);
  //Can't seem to do this
  timer.cancel();
  timer = new Timer();
  timer.schedule(new ExpiringTokentask(timer,sessionKey), EXPIRY_TIME);
  //Return token validation
  return true;
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top