Hello Timer!
If actors are to come alive and each act out their individual destinies, they must have a source of fuel, which in this context amounts to having access to a thread of execution. It's always possible to give actors an initial jolt in the main script so that they do something, as in the Hello World example, and they already react to these signals in their own time (asynchronously), but how do they keep going?
The dependency exchange must have a timer actor introduced, and that is done with a one-line command:
Since the timer is an actor, the other actors must interact with it in the familiar way, but expressing a need for an outside interface.
private TimerOutside timer
void needTimer(TimerOutside timer) {
this.timer = timer
}
|
The timer interface offers three straightforward methods which allow an actor to set itself up to do work in the future. All of these methods involve a closure which is called later, and sometimes even repeatedly. The callback can happen at a given time, or after a certain waiting time, or every so often.
public interface TimerOutside {
void eventAt(long time, Closure closure);
void eventIn(long time, Closure closure);
void eventEvery(long time, Closure closure);
}
|
Two of the three methods are used in the only function of the trivial TimerActor. First a random pause is created using timer.eventIn(), and then a call is made to timer.eventEvery() in order to cause a repeated callback.
void go() {
def shortly = (long)(200+Math.random()*300)
println "$name go in $shortly!"
timer.eventIn(shortly) {
println "$name heartbeat!"
timer.eventEvery(200) {
println "I'm $name!"
}
}
}
|
All that's left to do is call this go() method once for each actor so that they can set up to receive all the future timer callbacks.
for ( actor in actors ) {
actor.go()
}
|
That's all there is to it! With this closure-based timer system, the code for interaction with the timer is as probably as nice as it could possibly be.
|