【问题标题】:Is it really so hard to "postpone" a task (or "wait for idle")“推迟”任务(或“等待空闲”)真的那么难吗?
【发布时间】:2013-03-11 12:41:04
【问题描述】:

如何使用属性完成“等待空闲”模型:

  • 当调用do()方法时,经过X延迟,会调用close()方法。
  • 如果我 X 时间过去之前再次调用do() 方法,则必须推迟对close() 的调用。

示例

场景 1:(超时 = 10 秒):

  1. 用户在0时调用do()
  2. 在时间10,调用close()方法,因为用户没有再次调用do()

场景 2:(也超时 = 10 秒):

  1. 用户在0 时调用do()。 (所以在10 应该调用close() 方法)。
  2. 8时,用户再次调用do()
  3. 10 时没有任何反应,因为 close() 被推迟了 10 秒。
  4. 18时刻,close()方法被调用,因为自从8之后用户没有再次调用do()

我尝试过的:

private static final long delay = 10000;
private Timer t;
private TimerTask tt;

public void do() {

    ...

    // check old timer first:
    if (t != null) t.cancel();

    // create new timer
    t = new Timer();
    tt = new TimerTask() {
        @Override
        public void run() {
            close();
        }
    }
    // run it
    t.schedule(tt, System.currentTimeMillis() + delay);
}
private void close() {
    // do some cleanup here
}

这段代码非常难看。 这也是非常低效和消耗内存的,因为 do() 函数每秒被调用大约 50 次。

我应该怎么做才能让这项工作以一种高效而整洁的方式工作? (真的有那么难吗?)

【问题讨论】:

  • 你为什么一遍又一遍地创建Timer?您应该重复使用一个计时器,并且只在其上取消/安排任务。当你解决这个问题时,不会有任何低效和消耗内存的问题。
  • Exception in thread "main" java.lang.IllegalStateException: Task already scheduled or cancelled
  • @MarkoTopolnik - 您无法在已取消的计时器上安排任务。
  • @Perception 当然。这就是为什么您不要取消计时器。你取消了任务。
  • @MarkoTopolnik - 没关系,我知道你在哪里说任务与计时器。

标签: java timer scheduled-tasks


【解决方案1】:

你走在正确的道路上,这并不难。

这是我想向您提出的建议。只创建一次计时器。使其成为班级成员。在构造函数中创建它的实例。

当方法被调用时,像现在一样创建一个任务。但是,您可以创建单独的类,甚至可以提前创建它的实例,当调用 do() 方法时只需安排它,因此将根据您的安排调用 close()

do() 被调用时,取消之前创建的关闭任务。这将确保在再次调用方法 do() 时不会关闭任何内容。

顺便说一句,因为do 是java 中的保留字,所以不能以这种方式调用方法。这意味着您的代码甚至无法编译。更改名称。

【讨论】:

  • 我明白了,但是我不完全理解第三段,我应该在我的 do() 方法中做什么(以及在单独的类中做什么)? (而且命名只是因为我直接写代码,没想到)。
【解决方案2】:

open()时设置10秒定时任务

保留一个变量long lastCall,该变量从doIt() 设置为System.currentTimeMillis()

在时间任务体中,检查lastCall是否在10秒内。如果是这样,重新安排定时器任务的剩余时间。如果没有,请致电close()

当您读取或写入lastCall 时,不要忘记synchronize

【讨论】:

    【解决方案3】:

    我找到了合适的解决方案:

    public class TimerExample {
    
        private TimerTask tt;
        ScheduledFuture<?> future;
        private ScheduledThreadPoolExecutor s;
    
        public TimerExample() {
            s = new ScheduledThreadPoolExecutor(1);
            tt = new TimerTask() {
    
                @Override
                public void run() {
                    close();
                }
            };
            doSomething();
        }
    
        public void doSomething() {
            if (future != null) future.cancel(true);
            future = s.schedule(tt, 3000, TimeUnit.MILLISECONDS);
            System.out.println("do");
        }
    
        public void close() {
            System.out.println("Close");
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-02
      • 1970-01-01
      • 2016-04-07
      • 1970-01-01
      • 2023-02-03
      相关资源
      最近更新 更多