Two examples are presented: in the first one, a ball draws a circle as result of being moved by two distinct fair threads; the second example shows the use of broadcast events and of dynamic creation of objects.
The first example has also been coded using standard Java threads; click here to get the description of it.
The two examples are also coded using the reactive programming framework Junior; you can click here to see what the two examples coded in Junior look like.
Demo1 |
Two fair threads are moving the same ball; one thread
follows a sine path, and the other a cosine path. An applet is created
which adds a third fair thread, for painting traces of the ball. At
each phase, color of the ball changes, to visualize ball moves. One
gets a circle; this is basically because the scheduler running the two
threads is fair.
The Ball
class Ball
{
double x, y, angleX = 0, angleY = 0;
int radius = 8, steps = 100, scale = 5;
Color color;
public Ball(int x,int y,Color color){
this.x = x; this.y = y; this.color = color;
}
public Ball(int x,int y){ this(x,y,ColorBall.nextColor()); }
public void paint(Graphics g){
g.setColor(color);
g.fillOval((int)x-radius, (int)y-radius,radius*2,radius*2);
}
public void sine(){
angleY += (2*Math.PI/steps);
y += scale*Math.sin(angleY);
}
public void cosine(){
angleX += (2*Math.PI/steps);
x += scale*Math.sin(angleX+Math.PI/2);
}
}
class Sin extends FairThread { Ball ball; public Move(Ball b){ ball = b; } public void run(FairScheduler scheduler){ while(true){ ball.sine(); cooperate(); } } }
class Updating implements Fair { Applet applet; public Updating(Applet a){ applet = a; } public void run(FairScheduler scheduler,FairThread thread){ while(true){ applet.paint(applet.getGraphics()); thread.cooperate(); } } }
public class Circle extends Applet { FairScheduler scheduler = new FairScheduler() Ball ball = new Ball(startx,starty); public void paint(Graphics g) { super.paint(g); ball.paint(g); ball.color = ColorBall.nextColor(); } void figure(Ball ball){ new Sin(ball).start(scheduler) new Cos(ball).start(scheduler) } public void init(){ new FairThread(new Updating(this)).start(scheduler) new FairThread(){ public void run(FairScheduler scheduler){ figure(ball); } }.start(scheduler); } }
Adding a new fair thread that move the ball following a cosine path, one gets a Lissajous figure (produced by two cosine and one sine threads):
public class Lissajous extends Circle { void figure(Ball ball){ super.figure(ball); new Cos(ball).start(scheduler); } }
Demo2 |
Balls are now dynamically created; they have two associated fair
threads which are waiting for an event to start moving (following a
sine or a cosine path). A button is used to create new balls at random
positions; the sine button broadcasts the sine event to all fair
threads; the cosine button broadcasts the cosine event; the
sine+cosine button broadcasts both sine and cosine events.
Mouse click -> event
public class GenerateAdapter extends MouseAdapter
{
FairScheduler scheduler;
Vector events;
public GenerateAdapter(FairScheduler scheduler,Vector events){
this.scheduler = scheduler; this.events = events;
}
public void mouseClicked(MouseEvent evt){
Enumeration enum = events.elements();
while(enum.hasMoreElements()){
String event = (String)enum.nextElement();
scheduler.broadcast(event);
}
}
}
Waiting Thread
class AwaitSin extends Sin
{
Ball ball;
String event;
public AwaitSin(Ball b,String s){ super(b); event = s; }
public void run(FairScheduler scheduler){
await(event);
super.run(scheduler);
}
}
public class CreateBall extends MouseAdapter { DynSinCos applet; public CreateBall(DynSinCos a){ applet = a; } public void mouseClicked(MouseEvent evt){ applet.createBall(); } }
public class DynSinCos extends Applet { int rand(int n){ return (int)(Math.random()*1000)%n; } FairScheduler scheduler = new FairScheduler(); Vector items = new Vector(); public void paint(Graphics g){ synchronized(items){ Enumeration enum = items.elements(); while(enum.hasMoreElements()) ((Ball)enum.nextElement()).paint(g); } } void createBall(){ Ball ball = new Ball(rand(size().width),rand(size().height)); ball.radius = 5; items.addElement(ball); new AwaitSin(ball,"sin").start(scheduler); new AwaitCos(ball,"cos").start(scheduler); } public void init(){ Button sin = new Button("sin"); Button cos = new Button("cos"); Button sincos = new Button("sin+cos"); Button start = new Button("new ball"); Vector params = new Vector(); params.addElement("sin"); sin.addMouseListener(new GenerateAdapter(scheduler,params)); params = new Vector(); params.addElement("sin"); params.addElement("cos"); sincos.addMouseListener(new GenerateAdapter(scheduler,params)); params = new Vector(); params.addElement("cos"); cos.addMouseListener(new GenerateAdapter(scheduler,params)); start.addMouseListener(new CreateBall(this)); Panel p = new Panel(); p.setBackground(Color.lightGray); setLayout(new BorderLayout()); p.setLayout(new GridLayout(1,5,5,20)); add("South",p); p.add(sin); p.add(cos); p.add(sincos); p.add(start); new FairThread(new Updating(this)).start(scheduler); createBall(); } }
Sources |
Click here to get the source code of the demos.