如何使用Java定时器放弃快速连续完成的所有任务(最后一个任务除外)

如何使用Java定时器放弃快速连续完成的所有任务(最后一个任务除外),java,timer,openhab,Java,Timer,Openhab,如果我没有正确解释这一点,请帮助我纠正我的问题。我的问题可能与Java定时器有关,也可能与一般问题解决有关 亲爱的读者,您不需要理解什么是OpenHAB,什么是OpenHAB规则,或者实际上MQTT是做什么的。但无论如何,我会用这些术语来设置我的问题的场景 在OpenHAB中,我有一个规则,用于响应发布到MQTT主题的消息。当我关闭调光器时,会向代理发送一组down MQTT消息。每条消息触发一条OpenHAB规则,该规则读取灯光的当前值并减去1,然后将其写回 为了确保规则不会在不同线程中同时触

如果我没有正确解释这一点,请帮助我纠正我的问题。我的问题可能与Java定时器有关,也可能与一般问题解决有关

亲爱的读者,您不需要理解什么是OpenHAB,什么是OpenHAB规则,或者实际上MQTT是做什么的。但无论如何,我会用这些术语来设置我的问题的场景

在OpenHAB中,我有一个规则,用于响应发布到MQTT主题的消息。当我关闭调光器时,会向代理发送一组down MQTT消息。每条消息触发一条OpenHAB规则,该规则读取灯光的当前值并减去1,然后将其写回

为了确保规则不会在不同线程中同时触发,从而防止灯光以正确的速率变暗,我的一位同事建议我添加lock.lock,如下所示:

rule "ArduinoBedroomVector"
    when
        Item Bedroomvector received update
    then
        lock.lock()
        try {
          // rules here
          var Number lightcircuit1level = BedroomCeilingLight.state as DecimalType
          switch(Bedroomvector.state) {
            case "light_1_up" : {
              lightcircuit1level = lightcircuit1level + 3
              if(lightcircuit1level>100) lightcircuit1level = 100
              sendCommand(BedroomCeilingLight, lightcircuit1level);
            }
            case "light_1_down" : {
              lightcircuit1level = lightcircuit1level -3
              if(lightcircuit1level<0) lightcircuit1level = 0
              sendCommand(BedroomCeilingLight, lightcircuit1level);
            }
          }
        }
        finally {
          lock.unlock()
        }
    end
这是一种享受

现在,我的执行器不会错过向下的消息

但是,由于执行器在433MHz射频传输过程中需要一段时间来响应每个单独的消息,因此发送每个射频消息需要0.5秒,发送到执行器的调光命令正在排队

因此,我需要介绍一种检查规则是否在最后运行的方法,例如0.6秒。如果有,则增加值,但不发送命令。如果没有,则增加值并最终发送命令

例如,这意味着我可以不断地上下调暗灯光,只要我不停下来,灯光级别就不会改变。然后,一旦我决定停止向上或向下调光,灯光级别将最终确定并设置

更好的是一个计时规则,允许我不断地改变水平,但仅根据最新水平每0.5秒设置一次灯光水平


我确信这只是创建一个在运行规则时被检查的计时器的一个例子,但是我不能确定何时应该创建和检查计时器。这对许多人来说可能是显而易见的。

不要对自己太苛刻,这不是显而易见的

我的方法是保留规则最近执行的时间戳,并在调用sendCommand之前添加一个if语句,以检查是否至少经过了.6秒

然而,有一种情况是,若最后一次收到命令的时间是在.6秒之前,那个么新值将永远不会被发送,所以我们需要设置一个计时器来发布最后一个值。但是,我们需要清理计时器,以便在设置计时器后收到新命令但尚未启动时,它不会启动。边缘案例很混乱

var lastExec = now.millis
var Timer timer = null

rule "ArduinoBedroomVector"
when
    Item Bedroomvector received update
then
    lock.lock()
    try {
      // rules here
      var Number lightcircuit1level = BedroomCeilingLight.state as DecimalType
      switch(Bedroomvector.state) {
        case "light_1_up" : {
          lightcircuit1level = lightcircuit1level + 3
          if(lightcircuit1level>100) lightcircuit1level = 100
          // Wait to send the new value
        }
        case "light_1_down" : {
          lightcircuit1level = lightcircuit1level -3
          if(lightcircuit1level<0) lightcircuit1level = 0
          // wait to send the new value
        }
      }

      // if more than .6 seconds have passed since the last time the value was sent
      if((now.millis - lastExec) > 600){
        // cancel the timer if one is already set
        if(timer != null) {
          timer.cancel
          timer = null
        }
        sendCommand(BedroomCeilingLight, lightcircuit1level)
        lastExec = now.millis
      }
      // its too soon to send the update, set a timer
      else {
        // cancel the timer if one is already set
        if(timer != null) {
          timer.cancel
          timer = null
        }
        // set a timer to go off in what is left of the .6 secs since the last update
        var t = now.plusMillis(600) - lastExec
        timer = createTimer(now.plusMillis(t), [|
          sendCommand(BedroomCeilingLight, lightcircuit1level)
          lastExec = now.millis 
          // beware, there could be a race condition here as the timer
          // will execute outside of the lock. If the rule executes 
          // at the same time as the timer the most recent value of
          // lastExec may be overwritten with an older value. It should 
          // happen very rarely though and may not be a problem.
        ]
      }
    }
    finally {
      lock.unlock()
    }
end