2011-07-11 9 views
5

todos. Un hilo en un programa Java en el que estoy trabajando anima una caminata al azar en el espacio (o al menos, una vez que se resuelva este problema). Contiene los dos métodos siguientes:Problema relacionado con la persistencia de la variable entre los hilos en java

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

Entonces, si el indicador de pausa no está configurado, ejecuta el paso(). La única parte del paso() que debe observar son las pocas líneas sobre el objeto Alpha. (Alpha es una clase API que produce una función dependiente del tiempo que se usa para animar). Entonces step() crea un objeto Alpha, que luego alimenta a otro hilo llamado AlphaControl. AlphaControl le dice al programa que deje de calcular puntos hasta que este paso finalice. Hace esto estableciendo el indicador de pausa que está marcado en el método run().

¿Cuál es el problema? Tenga en cuenta que agregué una línea de depuración que verifica inmediatamente si el Alpha está terminado después de haber sido creado. Parece que esta línea de código nunca debería ejecutarse. ¿Terminó el Alfa? Por supuesto que no, simplemente lo creamos. Pero esta línea se ejecuta cada vez que se llama a la función DESPUÉS de la primera vez. De alguna manera, está colgando en la misma instancia Alpha y usándola una y otra vez. Supongo que esto se debe a la referencia al Alfa que todavía está vivo en el subproceso AlphaControl.

Entonces, ¿cómo puedo arreglar esto? He intentado varias cosas. Creé una gran variedad de Alfas, las inicialicé todas antes de que comenzara la caminata, y traté de decirle que use una alfa diferente de la matriz en cada paso, pero esto tuvo el mismo resultado. También intenté usar AlphaControl para establecer alfa a nulo antes de que se cierre, pero tampoco funcionó. ¿Es posible destruir este objeto? Para cuando el código step() vuelva a funcionar, debe hacerse el AlphaControl que se creó la primera vez y esperar la recolección de basura.

Además, en caso de que fuera útil verlo, aquí está la clase AlphaControl.

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

} 

Gracias de antemano por cualquier ayuda. Jeff

+3

No mostró el código para 'Alpha': ¿Está seguro de que' alpha.finished() 'devuelve' false' directamente después de construir 'alpha'? Y 'alpha.setLoopCount (1);' tampoco lo establece en 'false'? – Howard

+1

también podría ayudar ver la fuente de Alpha. – nojo

+0

¿Intentó depurar su código? si no, por favor hazlo una vez. –

Respuesta

0

No estoy seguro si sigo completamente la intención del programa, pero parece que tiene una condición de carrera. Cuando llame a ac.start() en su objeto AlphaControl, existe no garantía de que gw.pause se establecerá antes de la próxima ronda de su ciclo de ejecución. De hecho, hay una buena probabilidad de que el ciclo se ejecute muchas veces antes de que se establezca gw.pause.

Solo para las patadas, sugiero llamar ac.run() en lugar de ac.start() en un recorrido, como un atajo para quitar el enhebrado de la imagen. Si se produce el comportamiento previsto, me gustaría ver su razón para hacer esto en varios hilos en lugar de uno solo.

0

Creo que el problema es una de las dos cuestiones:

estado
  • Alpha 's se mantiene como una variable estática, lo que significa que es el misma para todas las instancias de Alpha, y es muy probable que no reiniciándolo en el constructor (con razón).
  • Alguna parte de su estado no está marcado volatile, que rompe la semántica del compilador se basa en saber que una marcada campo requerirá siempre una búsqueda de valor fresca (de lo contrario el compilador es libre para almacenar en caché el valor)
2

Creo que la clave para entender por qué falla el código es entender qué hace la clase Alpha de la biblioteca Java3D. De su pregunta, me parece que no la entiende correctamente. No hace un bucle. Si comprueba el código fuente (http://www.java2s.com/Open-Source/Java/6.0-JDK-Modules/java-3d/javax/media/j3d/Alpha.java.htm), verá que no contiene una sola estructura de bucle. Lo que hace, es definir una función que asigna un valor de tiempo a un valor en el rango [0,1].

Si nos fijamos en la fuente del método terminado():

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

se aprecie que su valor depende de cuando se le llama.

Y como básicamente definió su alfa para tener 1 bucle de 1 milisegundo, comenzando desde el momento de la creación, no se terminará durante 1 milisegundo después de crear ese alfa, y terminará para siempre.

Espero que esto ayude.

Cuestiones relacionadas