Two threads are moving the same ball;; one thread follows a
sine path, and the other a cosine path. Color of the ball changes each
time it is painted, to visualize the ball moves. One expects a
circle...
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 Thread
{
Ball ball;
Applet applet;
public Sin(Ball b,Applet a){ ball = b; applet = a; }
public void run(){
while(true){
ball.sine();
applet.paint(applet.getGraphics());
}
}
}
public class SinCos extends Applet
{
Ball ball = new Ball(startx,starty);
public void paint(Graphics g) {
super.paint(g);
ball.paint(g);
ball.color = ColorBall.nextColor();
}
void circle(Ball ball){
new Sin(ball,this).start();
new Cos(ball,this).start();
}
public void init(){ circle(ball); }
}
Warning! "If you are using Netscape, avoid to press on the
button, as you could get completely stuck! Instead, go ahead, and see
the section 'The Solution'
result
Interpretation: as the two threads do not cooperate in any way,
it is the scheduler task to switch from one to the other. Switches
occur at arbitrary moments that are visualized by lines and colums in
the output. In any case, one does not get a circle.
class Sin extends Thread
{
Ball ball;
Applet applet;
public Sin(Ball b,Applet a){ ball = b; applet = a; }
public void run(){
while(true){
ball.sine();
applet.paint(applet.getGraphics());
Thread.yield();
}
}
}
result
Interpretation:
now, the two threads cooperate by returning control to the scheduler
after each move. However, the scheduler has complete freedom to choose the next thread
to run. Moreover, switches can still occur at arbitrary moments. This solution would
certainly works with a cooperative scheduler, but, one looks for a portable solution.
By the way, the output shows that sine+cosine=square is a possible solution with
standard Java threads...
class Sin extends Thread
{
Ball ball;
Applet applet;
public Sin(Ball b,Applet a){ ball = b; applet = a; }
public void run(){
while(true){
ball.sine();
applet.paint(applet.getGraphics());
try{
Thread.sleep(1);
}catch(Exception e){System.out.println(e);}
}
}
}
result
Interpretation: Using Thread.sleep forces the scheduler to choose the other thread as
next thread to run, because the running thread falls asleep for a while. But, it has
the choice when the two threads are awake, which occurs periodically (remember that
there is a third thread, behing the scene, for dealing with graphics). Thus, one gets
something wich is near a circle, but which is not a circle. Moreover, the output
depends on the value of the sleeping delay. One thus certainly cannot get a portable
solution in this way.
class Sin extends Thread
{
Ball ball;
Applet applet;
public Sin(Ball b,Applet a){ ball = b; applet = a; }
public void run(){
while(true){
synchronized(ball){
ball.sine();
applet.paint(applet.getGraphics());
ball.notify();
try{
ball.wait();
}catch(Exception e){System.out.println(e);}
}
}
}
}
result
Interpretation:
After having awaken the other thread, the currently running one falls
asleep, waiting to be awaken later by a notification on the ball. The two threads are
thus executed in turn. One gets a circle: sine+cosine=circle, which of course was the
expected solution. Note however that there are too much painting actions performed
because both threads are calling paint (this cannot be avoided as soon as a symetric
solution is searched).
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
Interpretation:
Now, there are three threads and the scheduler has no way to run them
at the same pace. One does not get a Lissajous figure, which is the expected output.
The question is: how to get such a figure? This would certainly need a more complex
solution, with phases during which the scheduler runs the three threads.
Alternatively, a solution consists in using FairThreads; see what it is by
clicking here.
Click
here
to get the
source code of the demos.