Programming with Java Fair Threads: sine+cosine=circle

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); 
    }
}

Sine Thread

class Sin extends FairThread
{
    Ball ball;
 
    public Move(Ball b){ ball = b; }
    public void run(FairScheduler scheduler){
       while(true){
          ball.sine();
          cooperate();
       }
    }
}

Updating Class

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();
       }
    }
}

The Applet

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);
    }
} 
 
result

Adding a New Thread

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);
   }
}
result

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);
    }
}

Ball Creation

public class CreateBall extends MouseAdapter
{
   DynSinCos applet;
   public CreateBall(DynSinCos a){ applet = a; }
   public void mouseClicked(MouseEvent evt){ applet.createBall(); }
}
 

The applet

 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();
    }
}
result

Sources

Click here to get the source code of the demos.



This Html page has been produced by Skribe.
Last update Mon Oct 23 12:08:42 2006.