Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problem related to variable persistence between threads in java

Tags:

java

all. A thread in a Java program I am working on animates a random walk in space (or at least, it will once this problem is resolved). It contains the following two methods:

public void run() {
    while(gw.checkBoundingBox()) {
        if(!gw.pause) step();
    }       
}

public void step() {

    Point3d p1, p2;

    //get the last point, step, get the new point
    p1 = new Point3d(gw.position);
    gw.randomStep();
    p2 = new Point3d(gw.position);

    //create the Alpha that will do the animation, and wrap it in an AlphaControl,
    //which will set this object's pause flag until the Alpha finishes
    Alpha alpha = new Alpha();
    alpha.setLoopCount(1);

    if(alpha.finished()) System.out.println("DEBUG: I'm already dead.");

    AlphaControl ac = new AlphaControl(alpha,gw);
    ac.start();

    //create a piece of the path, attach an interpolator to do the animation
    PathCyl cyl = new PathCyl(p1,p2);

    StretchInterpolator si = new StretchInterpolator(alpha, cyl.anchor);
    si.setSchedulingBounds(new BoundingSphere(new Point3d(0,0,0),50));
    cyl.anchor.addChild(si);

    //put it all together
    BranchGroup b = new BranchGroup();
    b.addChild(cyl.tg);
    trans.addChild(b);  
}

So if the pause flag is not set, it runs step(). The only part of step() that you need to look at is the few lines about the Alpha object. (Alpha is an API class that produces a time-dependent function used for animating). So step() creates an Alpha object, which it then feeds to another thread called AlphaControl. AlphaControl tells the program to stop calculating points until this step is done animating. It does this by setting the pause flag that is checked in the run() method.

So what's the problem? Note that I added a debug line that immediately checks if the Alpha is finished after it is created. It seems like this line of code should never execute. Is the Alpha finished? Of course not, we just created it. But this line executes every time that the function is called AFTER the first time. Somehow it is hanging onto the same Alpha instance and using it over and over. I assume that this is because of the reference to the Alpha that is still alive in the AlphaControl thread.

So how do I fix this? I have tried several things. I created a huge array of Alphas, initialized them all before the walk even started, and tried to tell it to use a different alpha from the array at every step, but this had the same result. I also tried using the AlphaControl to set alpha to null before it closes, but this didn't work either. Is it possible to destroy this object? By the time the step() code gets back to running again, the AlphaControl that was created the first time around should be done and waiting for garbage collection.

Also, just in case it would be helpful to see it, here is the AlphaControl class.

public class AlphaControl extends Thread {

public Alpha alpha;
public GraphicalWalker gw;

public AlphaControl(GraphicalWalker gw, Alpha alpha) {
    this.gw = gw;
    this.alpha = alpha;
}

public void run() {

    boolean stop = false;
    boolean finished;

    while(!stop) {
        finished = alpha.finished();

        if( !finished && !gw.pause ) gw.pause = true;
        if( finished && gw.pause )   gw.pause = false;
        if(finished) stop = true;
    }
}

}

Thanks in advance for any help. Jeff

like image 685
jfrazier Avatar asked Nov 05 '22 18:11

jfrazier


1 Answers

I think key to understanding why your code fails is understanding what the Alpha class of the Java3D library does. From your question it seems to me you do not understand it correctly. It does not loop. If you check the source code (http://www.java2s.com/Open-Source/Java/6.0-JDK-Modules/java-3d/javax/media/j3d/Alpha.java.htm) you will see it does not contain a single loop structure. What it does do, is define a function that maps a time value to a value in the range [0,1].

If you look at the source of the finished() method :

    /**
     * Query to test if this alpha object is past its activity window,
     * that is, if it has finished looping.
     * @return true if no longer looping, false otherwise
     */
    public boolean finished() {
        long currentTime = paused ? pauseTime : J3dClock.currentTimeMillis();
        return ((loopCount != -1) &&
           ((float)(currentTime - startTime) * .001f > stopTime));
    }

you notice that its value depends on when it is called.

And since you basically defined your alpha to have 1 loop of 1 millisecond, starting from the time of creation it will not be finished for 1 millisecond after you create that alpha, and finished ever after.

I hope this helps.

like image 149
bowmore Avatar answered Nov 11 '22 05:11

bowmore