Execution limiter using lambda

Execution limiter class may help in situations when something must be executed only once per specified time. Use cases:

  • Computing large data and want to print progress only every 10 seconds
  • Inputs are changing often but you do not wan’t to calculate result more often than once per second

Typical is to use variable storing time stamp of last execution and condition not allowing execution sooner than X. But that is not truly encapsulated solution, right? I use helper class, usage is following:

ExecutionsLimiter limiter = new ExecutionsLimiter(1000, false); 

for (int i=0;i<10000000;++i) { 
  limiter.tryExec(()->{ //printed at most once per second 
    System.out.printf("Current progress is %d\n", i); 
  });

  calcHeavyStuff(i); 
}

Class itself looks like:

public class ExecutionsLimiter { 
  private long lastRepeatTimestamp; 
  private long intervalMsec; 
  
  public ExecutionsLimiter(long intervalMsec, boolean mayExecImmediatelly) { 
    this.intervalMsec = intervalMsec; 
    this.timeSuplier = timeSuplier; 
    reset(mayExecImmediatelly); 
  } 
  
  public void tryExec(Runnable block) { 
    long currentTimestamp =System.currentTimeMillis(); 
    if (currentTimestamp - lastRepeatTimestamp > intervalMsec) { 
      lastRepeatTimestamp = currentTimestamp; 
      block.run(); 
    } 
  } 
  
  public void reset(boolean mayExecImmediatelly) { 
    lastRepeatTimestamp = mayExecImmediatelly ? Long.MIN_VALUE : System.currentTimeMillis(); 
  } 
}

There is also method reset(). It may be used for use case like:

  • Process files in directories and print current file every 5 seconds
  • Print at least one file per directory

In that case it may happen that second request won’t be fulfilled when processing time of some directories will be less than 5 seconds. Simple call limiter.reset(true) when entering directory will reset limiter and first tryExec will pass.

Using this tool, you can get rid of conditions in your code and make it cleaner and easier to understand.