JBullet NullPointer在单独的线程中进行步进仿真

时间:2014-05-05 20:24:58

标签: java multithreading nullpointerexception bulletphysics jbullet

我在我的游戏中有一个设置,其中物理在一个单独的线程中更新,其实现如下

物理处理器(物理线程)

public class PhysicsProcessor extends Runnable {
    private DynamicsWorld world;

    public PhysicsProcessor() {
        /* basic dynamics world setup with dvbt broadphase :P */
    }

    public synchronized getDynamicsWorld() { return world; }

    @Override
    public void run() {
        /* update time */

        //update phyics
        getDynamicsWorld().stepSimulation(/* delta time */);
    }
}

主线程中的对象创建示例

myPhysicsProcessor.getDynamicsWorld.addRigidBody(/* some rigid body created here */);

问题在于,当游戏运行时,偶尔会在“stepSimulation”的单独线程中获得空指针异常,这是由我的dbvt broadphase中的setAabb引起的。

是否有人对我可以采取哪些措施来防止此异常或如何解决此问题?

1 个答案:

答案 0 :(得分:0)

你可以从它的外观中创造世界final。然后,这将显示同步访问的无用性:

public class PhysicsProcessor extends Runnable {
    private final DynamicsWorld world;

    public synchronized DynamicsWorld getDynamicsWorld() { return world; } //why sync? it can't change
}

您会看到:myPhysicsProcessor.getDynamicsWorld().addRigidBody(...)同步在getDynamicsWorld()返回后停止。因此addRigidBody(...)在安全同步上下文之外调用。

不,您要做的是确保始终在 同步块中使用

@Override
public void run() {
    //update physics
    synchronized(this) {
      world.stepSimulation(/* delta time */);
    }
}

public void addBody(/*args here*/) {
    synchronized(this) {
      world.addRigidBody(/*args here*/);
    }
}

现在一个方法没问题,但如果你发现自己想要以这种方式在跑步者之外做很多DynamicsWorld的方法,或者只是想要另一个选择,那么这个方法不需要同步:

public interface IWorldRunable {    
  void run(DynamicsWorld world);    
}    

public class PhysicsProcessor extends Runnable {
    private final DynamicsWorld world;
    private final ConcurrentLinkedQueue<IWorldRunable> worldRunables = ConcurrentLinkedQueue<IWorldRunable>();

    public PhysicsProcessor() {
        /* basic dynamics world setup with dvbt broadphase :P */
    }

    @Override
    public void run() {
        /* update time */

        //run runables on world
        for(IWorldRunable runable : worldRunables)
          runable.run(world);

        //clear runables
        worldRunables.clear();

        //update phyics
        world.stepSimulation(/* delta time */);
    }

    public void do(IWorldRunable runnable) {
        worldRunables.add(runnable);
    }
}

然后你会这样做,添加一个正文:

myPhysicsProcessor.do(new IWorldRunable(){      
  @Override
  public void run(DynamicsWorld world){
     world.addRigidBody(...);
  }
});

它会在同一个线程上的下一个stepSimulation之前执行,所以没有线程担心。