Elegant non-linear task scheduling?
I'd like to schedule a task to happen frequently at first, then less frequently over time. I would prefer not to add a dependency to Quartz just for this.
With the standard Java library, the best I've come up with is a series of one-shot tas开发者_JAVA技巧ks, followed by a less-frequent linear schedule:
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
myRunnable = new MyRunnable();
executor.schedule( myRunnable, 0, TimeUnit.SECONDS );
executor.schedule( myRunnable, 5, TimeUnit.SECONDS );
executor.schedule( myRunnable, 10, TimeUnit.SECONDS );
executor.schedule( myRunnable, 15, TimeUnit.SECONDS );
executor.schedule( myRunnable, 30, TimeUnit.SECONDS );
executor.schedule( myRunnable, 45, TimeUnit.SECONDS );
executor.scheduleWithFixedDelay( myRunnable, 60, 300, TimeUnit.SECONDS );
Is there a more elegant approach?
You can let the task trigger its next execution and always increment some 'wait seconds' after each completion?
As an extension to what @dcn suggested, you can write a delegating class that does the scheduling:
public class NonLinearScheduling {
public static void taperingOffSchedule(final ScheduledExecutorService executor,
final Runnable task,
final long initialDelay,
final TimeUnit unit,
final double decayMultiplier) {
assert initialDelay > 0;
assert decayMultiplier > 1.0;
Runnable repeater = new Runnable() {
double nextDelay = initialDelay;
public void run() {
task.run();
nextDelay *= decayMultiplier;
executor.schedule(this, (long) nextDelay, unit);
}
};
executor.schedule(repeater, initialDelay, unit);
}
}
Note also that instead of the repeater
being an anonymous Runnable
, it can become a publicly known type that allows future scheduling to be cancelled, etc:
public interface Repeater extends Runnable {
void stopRepeating();
}
public class NonLinearScheduling {
public static Repeater taperingOffSchedule(...) { ... }
private static class NonLinearRepeater implements Repeater {
private final AtomicBoolean _repeat = new AtomicBoolean(true);
public void stopRepeating() {
_repeat.set(false);
}
public void run() {
if (_repeat.get()) {
...
}
}
}
}
精彩评论