线程执行顺序Java

时间:2012-03-07 12:30:54

标签: java multithreading initialization

PhysicsThread.java 启动一个新线程。 run方法执行initialize方法。这种方法创造了物理世界。之后,它启动一个while循环,以1000/60 = 16毫秒的间隔更新世界。但是,我在循环中得到nullpointerexception,因为它并不总是知道世界,即使我检查了它。 可以解释发生了什么吗?

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

}

1 个答案:

答案 0 :(得分:3)

我怀疑这可能取决于你的构造技术,这是一个反模式。在构造函数中,不应让this引用“转义”,因为其他线程可能会看到处于部分构造状态的对象。在这一点上,关于类的状态的所有投注都是关闭的,甚至总是为真的不变量(例如最终字段被设置为值)也可能不成立。

我想知道这里发生的事情是否可能是由于以下一系列事件造成的:

  • 调用构造函数并根据this启动新线程。
  • 新线程在被抢占之前运行,并完全执行init(设置dw)和loop的一半。
  • 主线程继续使用构造函数,并将dw设置为null,作为字段初始化的一部分。
  • 在计算出deltalastTime之后,衍生线程会继续,然后会看到dw的空值。

我有点怀疑那个完全的情况,因为我希望在构造函数体运行之前初始化字段。但是,在对象仍在构建期间访问字段似乎是一个非常糟糕的主意。

为了解决这个问题,我建议在构造函数中启动一个线程,而是让调用代码在之后启动线程,例如:

final PhysicsThread pt = new PhysicsThread();
final Thread t = new Thread(pt);
t.setPriority(Thread.MIN_PRIORITY);
t.start();

(另外,让init方法不是构造函数的想法通常是个坏主意 - 如果dw字段永远不会改变,为什么不执行{{1}的所有工作?在构造函数本身期间并将init标记为dw?这将更清晰,使代码更容易推理,因为VM保证在构造期间将完全设置值并且它永远不会更改如果你构建了很多这些实例并且从未真正运行它们,那么唯一的缺点就是性能损失 - 所以不要这样做。:)

此外,班级名称具有误导性,因为这不是final而是Thread。将其称为RunnablePhysicsTask之类的内容可以说更清晰。)