5.1 Hello World Example
5.2 Stopping Threads with Events
5.3 Generated Values
1. Introduction
2. Threads
3. Fair Thread Framework
4. Java FairThreads API
5. Examples
6. Links with Reactive Programming
7. Conclusion
|
Three examples are described. The first one is a very simple but
complete example in which two fair threads are run. In the second
example, one defines a preemption mechanism to stop a fair thread when
an event becomes present. The third example considers generated values
and defines a way to process them.
Here is a small example of a complete program that runs two fair
threads. The first one cyclically prints hello, , and the
second one prints world . The main method of the program first
creates a fair scheduler, and then starts the two threads in it.
import fairthread.*;
class Say extends FairThread
{
String msg;
public Say(String msg){ this.msg = msg; }
public void run(FairScheduler scheduler){
while(true){
System.out.print(msg);
cooperate();
}
}
}
public class HelloWorld
{
public static void main(String[] args){
FairScheduler scheduler = new FairScheduler();
scheduler.start(new Say("hello, "));
scheduler.start(new Say("world!\n"));
}
}
Several points are important:
-
Output is an infinite list of
hello, world messages. This is
because the first thread, after printing the first part of the message,
always leaves the processor and thus lets the second thread print the last
part of it.
- Output is always the same; the program is totally deterministic.
- Without the
cooperate() call in Say , the
program would enter in a loop, printing hello forever; cooperate() is mandatory because FairThreads is basically
cooperative.
Using the Fair interface, the previous program could be
equivalently written as:
import fairthread.*;
class Say implements Fair
{
String msg;
public Say(String msg){ this.msg = msg; }
public void run(FairScheduler scheduler,FairThread thread){
while(true){
System.out.print(msg);
thread.cooperate();
}
}
}
public class HelloWorld
{
public static void main(String[] args){
FairScheduler scheduler = new FairScheduler();
scheduler.start(new FairThread(new Say("hello, ")));
scheduler.start(new FairThread(new Say("world!\n")));
}
}
The main point is that, in this way, class Say can extend an other
class; this is not possible with the first program, as multiple
inheritance of classes is forbidden in Java.
5.2 Stopping Threads with Events
|
One defines a class Until which extends FairThread , with
an associated class Controller .
Until runs a method, called controlled ,
and starts an instance of Controller which stops the
Until thread when an event becomes present. Here is definition
of Until :
import fairthread.*;
public class Until extends FairThread
{
String event;
public Until(String event){ this.event = event; }
public void controlled(FairScheduler scheduler){}
public final void run(FairScheduler scheduler){
FairThread controller = new Controller(event,this);
scheduler.start(controller);
controlled(scheduler);
scheduler.stop(controller);
}
}
class Controller extends FairThread
{
FairThread controlled;
String event;
public Controller(String event,FairThread controlled){
this.event = event; this.controlled = controlled;
}
public void run(FairScheduler scheduler){
await(event);
scheduler.stop(controlled);
}
}
This example gives a hint of how one can program sophisticated
user-defined execution strategies for fair threads, using broadcast
events.
A scanner is a thread which is associated to one event and which runs
a special callback method each time a value is generated for the
event. The notion of a scanner comes from the new version of the
SugarCubes [5] framework. Scanners extends the following
Scanner class, redefining the callback method:
public class Scanner extends FairThread
{
String event;
public Scanner(String event){ this.event = event; }
void callback(Object obj){}
public void run(FairScheduler scheduler){
while(true){
await(event);
while(true){
Object obj = nextValue(event);
if (obj == null) break;
callback(obj);
}
}
}
}
At each phase, all generated values are processed during it; moreover,
after the processing of the last value, the call of nextValue blocks, waiting
for the next phase to return the null value.
|