ScheduledExecutorService意外行为

时间:2017-12-03 20:39:11

标签: java android

我有以下代码段,使用ScheduledExecutorService每3'000毫秒运行一次,检查是否应该调用函数onOutTimeout()。至少这是个主意。

 private void launchOutTimeoutChecker(){
    Runnable check = new Runnable() {
        @Override
        public void run() {
            float bonus = 0;
            if(firstOutTime){bonus = timeout_initial_bonus;}
            float temp = System.currentTimeMillis() - lastOutTime;
            if(temp < timeout + bonus){
                if(Debug.logKeepalivePackets){
                    Log.d("keepalive", "firstOutTime: "+firstOutTime+"\ntime passed: "+temp);
                }
                // don't timeout yet, launch new execution
                launchOutTimeoutChecker(); // yey recursion?!
            } else {
                if(Debug.logKeepalivePackets){
                    Log.d("keepalive", "TIMEOUT!\nfirstOutTime: "+firstOutTime+"\ntime passed: "+temp);
                }
                onOutTimeout();
            }
        }
    };

    // before the first message, give a bonus of timeout_initial_bonus
    long bonus = 0;
    if(firstOutTime){bonus = timeout_initial_bonus;}
    long time_out = bonus + timeout;
    futureOut = executorOut.schedule(check, time_out, TimeUnit.MILLISECONDS);

    // the task is now scheduled. after the timeout will it check whether it should actually trigger a timeout.
    // the ScheduledFuture could be used to cancel this again
}

编辑:我设置lastOutTime的位置在我的(runnable)类的run方法中。方法lastInTimeoutChecker不会打印任何内容。

    @Override
public void run() {
    // initialize executors that are used in launchOutTimeoutChecker and launchInTimeoutChecker
    executorIn = Executors.newSingleThreadScheduledExecutor();
    executorOut = Executors.newSingleThreadScheduledExecutor();

    // start the timers in new threads
    this.lastOutTime = System.currentTimeMillis();
    launchOutTimeoutChecker();
    this.lastInTime = System.currentTimeMillis();
    launchInTimeoutChecker();

}

我希望每3秒钟看一条日志消息,因为timeout设置为3,实际上日志消息大约每3秒发生一次。 但是为什么这个输出说过的时间是0.0?

12-03 20:16:51.049 19578-19658/ch.ethz.inf.vs.a4.minker.einz D/keepalive: firstOutTime: false
                                                                          time passed: 0.0
12-03 20:16:54.051 19578-19658/ch.ethz.inf.vs.a4.minker.einz D/keepalive: firstOutTime: false
                                                                          time passed: 0.0
12-03 20:16:57.052 19578-19658/ch.ethz.inf.vs.a4.minker.einz D/keepalive: firstOutTime: false
                                                                          time passed: 0.0
12-03 20:17:00.054 19578-19658/ch.ethz.inf.vs.a4.minker.einz D/keepalive: firstOutTime: false
                                                                          time passed: 0.0
12-03 20:17:03.055 19578-19658/ch.ethz.inf.vs.a4.minker.einz D/keepalive: firstOutTime: false
                                                                          time passed: 0.0
12-03 20:17:06.056 19578-19658/ch.ethz.inf.vs.a4.minker.einz D/keepalive: firstOutTime: false
                                                                          time passed: 0.0
12-03 20:17:09.057 19578-19658/ch.ethz.inf.vs.a4.minker.einz D/keepalive: firstOutTime: false
                                                                          time passed: 0.0
12-03 20:17:12.058 19578-19658/ch.ethz.inf.vs.a4.minker.einz D/keepalive: firstOutTime: false
                                                                          time passed: 0.0
12-03 20:17:15.059 19578-19658/ch.ethz.inf.vs.a4.minker.einz D/keepalive: firstOutTime: false
                                                                          time passed: 0.0
12-03 20:17:18.060 19578-19658/ch.ethz.inf.vs.a4.minker.einz D/keepalive: firstOutTime: false
                                                                          time passed: 0.0
12-03 20:17:21.061 19578-19658/ch.ethz.inf.vs.a4.minker.einz D/keepalive: firstOutTime: false
                                                                          time passed: 0.0
12-03 20:17:24.062 19578-19658/ch.ethz.inf.vs.a4.minker.einz D/keepalive: firstOutTime: false
                                                                          time passed: 0.0
12-03 20:17:27.064 19578-19658/ch.ethz.inf.vs.a4.minker.einz D/keepalive: firstOutTime: false
                                                                          time passed: 0.0
12-03 20:17:30.067 19578-19658/ch.ethz.inf.vs.a4.minker.einz D/keepalive: firstOutTime: false
                                                                          time passed: 0.0
12-03 20:17:33.068 19578-19658/ch.ethz.inf.vs.a4.minker.einz D/keepalive: firstOutTime: false
                                                                          time passed: 0.0
12-03 20:17:36.071 19578-19658/ch.ethz.inf.vs.a4.minker.einz D/keepalive: firstOutTime: false
                                                                          time passed: 0.0
12-03 20:17:39.072 19578-19658/ch.ethz.inf.vs.a4.minker.einz D/keepalive: firstOutTime: false
                                                                          time passed: 0.0
12-03 20:17:42.074 19578-19658/ch.ethz.inf.vs.a4.minker.einz D/keepalive: firstOutTime: false
                                                                          time passed: 0.0
12-03 20:17:45.076 19578-19658/ch.ethz.inf.vs.a4.minker.einz D/keepalive: TIMEOUT!
                                                                          firstOutTime: false
                                                                          time passed: 131072.0

大约一分钟后,终于出现超时消息,我原本期望将其作为第一条日志消息。通过它的时间表示始终完全 131072毫秒。

我根本不明白如何调试这个。我做了什么:

  • 确保只有一个周围类的实例正在运行。没有太大的改变(除了你现在看到的输出,而不是每个重复的消息,但其他一切都是相同的)

  • 确保lastOutTime仅设置一次,在第一次致电launchOutTimeoutChecker()之前,将其设置为System.currentTimeMillis()

  • firstOutTime目前始终为false,因此该部分应无关紧要

  • 起初,它按预期工作。然后我在调试模式下运行相同的代码,这发生了。现在按下常规运行时也会出现上述输出。

  • 重建没有解决它

  • 在真实设备而非模拟器上运行它会表现出相同的行为。

  • CPU使用率或内存使用率似乎没有显着变化

我的代码出了什么问题?

2 个答案:

答案 0 :(得分:1)

如果我理解了您的要求,您希望安排一个任务,该任务将以固定费率检查某些条件,以了解您是否应该调用名为onOutTimeout的某个函数。以下是此要求的简单解决方案:

  private long timeWhenYouShouldCallYourFunction;
  private ScheduledExecutorService service;

  private void launchOutTimeoutChecker() {
    Runnable check = new Runnable() {
      @Override
      public void run() {
        long currentTime = System.currentTimeMillis();
        System.out.println("ping " + currentTime);
        if (currentTime > timeWhenYouShouldCallYourFunction) {
          onOutTimeout();
          service.shutdown();
        }
      }
    };

    int randomShift = Math.abs(new Random().nextInt() % 10_000);
    System.out.println("Shift is " + randomShift + " msec");
    timeWhenYouShouldCallYourFunction = System.currentTimeMillis() + randomShift;
    service = Executors.newSingleThreadScheduledExecutor();
    service.scheduleAtFixedRate(check, 0, 3000, TimeUnit.MILLISECONDS);
  }

  private void onOutTimeout() {
    System.out.println("Made it!");
  }

答案 1 :(得分:1)

尽量不要使用float毫秒。 System.currentTimeMillis()会返回long,这可能会给您带来麻烦。