代码之家  ›  专栏  ›  技术社区  ›  whatnick

取消计时器

  •  3
  • whatnick  · 技术社区  · 15 年前

    我已经实现了一个分配固定数量令牌的令牌系统。分配时的每个令牌都会启动一个计时器,该计时器将在几分钟后过期,并清除令牌槽以供重用。如果用户在计时器到期前验证令牌,则应取消计时器并用另一个令牌有效期重置。我似乎无法从计时器线程之外取消计时器,这是预期的行为。代码段如下:

    /**
     * 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
        }
    }
    
    4 回复  |  直到 8 年前
        1
  •  7
  •   jkdev james murphy    8 年前

    如前所述,您可以取消提交给计时器的计时器任务,而不是取消计时器,这样您就不必再增加新的计时器。

    你在做什么:

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

    将引发IllegalstateExceptions,因为不能在已取消的计时器上安排新任务。

    所以不要这样做:timer.cancel()。 让您的映射成为从会话键到时间任务的映射,并取消时间任务而不是计时器。这样,您就不必新建计时器,并且您的计时器将在取消一个或多个任务后按预期工作。您还可以使用一个计时器来处理多个会话。现在,您将为每个会话生成一个计时器,从而生成一个线程。

    另一方面,您不应该使用 java.util.Timer .如果您的任何TimerTask抛出异常会发生什么?你的计时器将被杀死,再也不会运行了!如果你的一个时间任务是慢的或者是无限期的阻塞呢?该计时器上的任何其他计时器任务都将无法执行。研究如何使用 ScheduledThreadPoolExecutor 相反。我确信JavaUTI.TIMER会被下一个Java发行版所否决。

        2
  •  2
  •   Prabhu R    15 年前

    我相信您可以使用一个计时器对象,创建尽可能多的计时器任务,而不是创建多个计时器。计时器成本很高,因此对整个应用程序使用一个或两个计时器就足够了。另外,您要取消计时器而不是计时器任务,请尝试取消计时器任务。

        3
  •  1
  •   brianegge    15 年前

    如果计时器不为空,则应该能够调用 cancel() 从任何线程。更好的方法是使用 ScheduledExecutorService 得到一个 Future 对于提交的每个任务。对于未来,您可以取消它,或者检查结果。

        4
  •  1
  •   Aaron Chambers    15 年前

    在您尝试取消计时器的行之后,您应该在调用schedule方法之前创建一个新的计时器。

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