1

I have an anonymous class and I want to access some variables of the outer class from the anonymous.The problem is that always when I try to access it, it has the same value as when it was initialized even that i am changing its value on an other anonymous class.

this is the trimmed code

public class WeaponCircle extends Entity {
    public static int TAG = gWorld.getNextTag();
    float power=99; // <<<--the variable
    public WeaponCircle(final gWorld world) {
        super(world);
        this.tag = TAG;

        setGroups(Scene.SLOWABLE);

        addMechanism(new IntervalMechanism(this,10) {
            @Override
            public void init() {
                super.init();
                    world.worldrenderer.setWorldShader("punchShockWave");
                    world.worldrenderer.getShader("punchShockWave").getShader().setUniformf("screenSize",  Tools.tempVec2.set(Gdx.graphics.getWidth(),Gdx.graphics.getHeight()));
                    power=4;
            }
            @Override
            public void die() {
                super.die();
                world.worldrenderer.setClearWorldShader();
            }
            @Override
            public void tick() {//this is called every frame
                if(power>0)power-=0.1f*Director.delta;
                Tools.con("debug0:"+power);    //<<--------------------debug0 ,prints correct value
            }
        });

        addMechanism(new MovementMechanism(this));

        addMechanism(new SpriteMechanism(this,"sprites/sprites.png",714,284,1,235,235,gWorld.RENDER_LAYER4));

        world.worldrenderer.addShader("punchShockWave", new Shader("shaders/default.ver","shaders/punch_shock_wave.frag",Shader.SCENE_SHADER));
        world.worldrenderer.getShader("punchShockWave").setListener(new ShaderParrametersListener(this) {
            @Override
            public void setParameters(Shader shader) {//called every frame
                WeaponCircle wc=(WeaponCircle)entity;//entity is the object that i passed in the constractor
                /*irrelevant code*/
                Tools.con("debug1:"+wc.power);  //<<--------------------debug1 ,prints always 99
                Tools.con("debug2:"+power);   //<<--------------------debug2 ,prints always 99
                /*irrelevant code*/
            }
        });
    }
}

ShaderParrametersListener (its a static class inside the Shader class)

public abstract static class ShaderParrametersListener{
    public Entity entity;
    abstract public void setParameters(Shader shader);
    public ShaderParrametersListener(){};
    public ShaderParrametersListener(Entity entity){this.entity=entity;}
}

My entity system is based on anonymus classes and I didnt had any problem so far ,If i use 1 more IntervlMechanism and print the power variable from there ,I will get the correct value.This happens only in the ShaderParrametersListener class.

14
  • 5
    if(power>0)power-=0.1f*Director.delta; - I'd urge you to consider the readability benefits of whitespace (and indeed braces). Commented Jul 5, 2014 at 8:08
  • 1
    Does IntervalMechanism declare a power field? Commented Jul 5, 2014 at 8:11
  • @Henry ,no it doesn't ,all the power appearances refer to the one inside WeaponCircle class, triple checked Commented Jul 5, 2014 at 8:14
  • What is the order that debug0, debug1, and debug2 are printed in? Commented Jul 5, 2014 at 22:52
  • @newacct ,the order is debug0,debug1,debug2 .Both tick and setParameters() are executing on the same event but setParameters() is the last called.Also everything runs on one thread. Commented Jul 6, 2014 at 6:56

1 Answer 1

1
+50

I think your issue is that you are using the this keyword inside the constructor. See Java - Leaking this in constructor.

As the linked answer says,

"An object is considered to be completely initialized when its constructor finishes. A thread that can only see a reference to an object after that object has been completely initialized is guaranteed to see the correctly initialized values for that object's final fields". No such guarantee if you leak this to another thread in the constructor! Also 'at the end of the constructor' may be reordered by the VM."

My guess is that world.worldrenderer.getShader("punchShockWave").setListener is the other thread that now has access to an incompletely constructed object.

I'd recommend finding a way to call the above setListener method after your constructor has completed.

UPDATE I see that the power field is not final, so that may invalidate my hypothesis, as the linked question seems to indicate this problem holds for final fields only; however, I still would attempt to wait until after the constructor completes before passing this to another object. Maybe try it out and see if it fixes the bug.

Sign up to request clarification or add additional context in comments.

4 Comments

wow ,I moved the setListener on the tick method(used a boolean 'first' to only call it once) so that it will be called after the constraction of the object has finished and the problem disappears, this is a very good answer ,good work, you will get the bounty in 13 hours...
I'm glad to hear it, SteveL.
I think I was not getting this issue on windows(now running linux) didn't mentioned it cause I was not sure, is this possible? possible that the windows implementation of the vm was doing something different with the threads management?Also I am not getting this problem (as mentioned in the question) in the case where I would access power from another IntervalMechanism anonymous class(or any other that extends WorldMechanism).Is it possible that in some implementations of the virtual machine I will get problems like the above even in this classes?
With my limited understanding of what's happening, I will still say "Yes, it is possible that you will still get problems in the other classes that are currently working." Concurrency is a difficult and tricky thing, and anything you can do to remove any uncertainty or possible errors is a GOOD THING.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.