Reputation: 67
PhysicsThread.java starts a new thread. The run method executes the initialize method. This method creates the physics world. After that, it starts a while loop that updates the world with an interval of 1000/60 = 16 milliseconds. However, I get a nullpointerexception
in the loop, because it does not always know world, even though I check for that. Can explain what is happening?
PhysicsThread.java
public class PhysicsThread implements Runnable {
long fps = 60;
DiscreteDynamicsWorld dw;
long lasttime = System.currentTimeMillis();;
static int maxPhysicsObjects = 50000;
PhysicsThread() {
Thread t = new Thread(this);
t.setPriority(Thread.MIN_PRIORITY);
t.start();
}
@Override
public void run() {
System.out.println("Start thread");
init();
System.out.println("Start threadloop");
while(true) {
loop();
}
}
public void init() {
BroadphaseInterface broadphase = new AxisSweep3_32(new Vector3f(0,0,0), new Vector3f(200000,200000,200000), maxPhysicsObjects);//new DbvtBroadphase();
DefaultCollisionConfiguration collisionConfiguration = new DefaultCollisionConfiguration();
CollisionDispatcher dispatcher = new CollisionDispatcher(
collisionConfiguration);
SequentialImpulseConstraintSolver solver = new SequentialImpulseConstraintSolver();
dw = new DiscreteDynamicsWorld(dispatcher, broadphase,
solver, collisionConfiguration);
System.out.println("Made world");
dw.setGravity(new Vector3f(0, 0, -10));
}
public void loop() {
if (dw!=null) {
float delta = System.currentTimeMillis()-lasttime;
lasttime = System.currentTimeMillis();
dw.stepSimulation(delta/1000f, 1, 1/60f);
}
try {
Thread.sleep(1000/fps);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public DiscreteDynamicsWorld getWorld() {
return dw;
}
}
Upvotes: 2
Views: 635
Reputation: 103797
I suspect this may be down to your construction technique, which is an antipattern. You shouldn't let the this
reference "escape" during a constructor, because then other threads may see the object in a partially-constructed state. At this point, all bets are off about the state of the class, and even invariants that are always true (such as final fields being set to a value) may not hold.
I wonder if what is happening here might be due to the following sequence of events:
this
.init
(setting dw
), and half of loop
, before being pre-empted.dw
to null
as part of field initialisation.delta
and lastTime
, then sees a null value for dw
.I'm a little hesistant to say that's exactly the case because I would have expected the fields to be initialised before the constructor body runs. However it seems likely that accessing the fields while the object is still being constructed is a very bad idea.
In order to fix this I'd suggest not starting a thread in the constructor, but rather having the calling code start the thread afterwards, e.g.:
final PhysicsThread pt = new PhysicsThread();
final Thread t = new Thread(pt);
t.setPriority(Thread.MIN_PRIORITY);
t.start();
(Also, the idea of having init
methods that aren't the constructor is usually a bad idea - if the dw
field never changes, why not perform all the work of init
during the constructor itself and mark dw
as final
? This will be cleaner and make your code easier to reason about, since the VM guarantees the value will be fully set during construction and that it will never change afterwards. The only downside is a performance hit if you construct lots of these instances and never actually run them - so just don't do that. :)
Plus the class name is misleading, since this isn't a Thread
but a Runnable
. Calling it something like PhysicsTask
or PhysicsSimulationRun
would arguably be clearer.)
Upvotes: 3