Old: minimize blocking - use ScheduledExecutorService
var scheduler = Executors.newScheduledThreadPool(1);
var future = scheduler.scheduleAtFixedRate(() -> {
System.out.println("Hello, World!");
}, 1, 2, TimeUnit.SECONDS);
New: embrace blocking - use Thread.sleep()
try (var scope = StructuredTaskScope.open()) {
var subtask = scope.fork(() -> {
for (var deadline = Instant.now().plusSeconds(1);;
deadline = deadline.plusSeconds(2)
) {
Thread.sleep(Duration.between(Instant.now(), deadline));
System.out.println("Hello, World!");
}
});
}
Now add abstraction: scheduleAtFixedRate
→ repeatAtFixedRate
public static <T> Callable<T> repeatAtFixedRate(
Runnable command,
Duration initialDelay,
Duration period
) {
return () -> {
for (var deadline = Instant.now().plus(initialDelay);;
deadline = deadline.plus(period)
) {
Thread.sleep(Duration.between(Instant.now(), deadline));
command.run();
}
};
}
// Usage:
try (var scope = StructuredTaskScope.open()) {
var subtask = scope.fork(repeatAtFixedRate(() -> {
System.out.println("Hello, World!");
}, Duration.ofSeconds(1), Duration.ofSeconds(2)));
}
Same goes for scheduleWithFixedDelay
→ repeatWithFixedDelay
public static <T> Callable<T> repeatWithFixedDelay(
Runnable command,
Duration initialDelay,
Duration delay
) {
return () -> {
Thread.sleep(initialDelay);
for (;;) {
command.run();
Thread.sleep(delay);
}
};
}
// Usage:
try (var scope = StructuredTaskScope.open()) {
var subtask = scope.fork(repeatWithFixedDelay(() -> {
System.out.println("Hello, World!");
}, Duration.ofSeconds(1), Duration.ofSeconds(2)));
}