Я подозреваю, что это может быть связано с вашей строительной техникой, которая является антипаттерном.Вы не должны позволять this
ссылаться на «escape» во время конструктора, потому что тогда другие потоки могут видеть объект в частично сконструированном состоянии.На этом этапе все ставки отключены относительно состояния класса, и даже инварианты, которые всегда являются истинными (например, для конечных полей устанавливается значение), могут не сохраняться.
Интересно, что здесь происходит?может быть из-за следующей последовательности событий:
- Вызывается конструктор и запускает новый поток на основе
this
. - Новый поток запускается и полностью выполняет
init
(установка dw
) и половина loop
, перед тем как быть прерванным. - Основной поток продолжает работу с конструктором и устанавливает
dw
в null
как часть инициализации поля. - порожденный поток продолжается после обработки
delta
и lastTime
, затем видит нулевое значение для dw
.
Я немного не согласен с тем, чтобы сказать, что это точно случай, потому что я ожидал, что поля будут инициализированы до запуска тела конструктора.Однако кажется вероятным, что доступ к полям во время создания объекта является очень плохой идеей.
Чтобы исправить это, я бы предложил не запуск потока в конструкторе,но, скорее всего, после того, как вызывающий код запустит поток позже, например:
final PhysicsThread pt = new PhysicsThread();
final Thread t = new Thread(pt);
t.setPriority(Thread.MIN_PRIORITY);
t.start();
(Кроме того, идея иметь init
методы, которые не являются конструкторами, обычно является плохой идеей - если dw
поле никогда не меняется, почему бы не выполнить всю работу init
во время самого конструктора и пометить dw
как final
? Это будет чище и облегчит ваш код, так как виртуальная машина гарантирует, что значение будет полностьюустанавливается во время построения и никогда не изменится после этого. Единственным недостатком является снижение производительности, если вы создаете много этих экземпляров и никогда не запускаете их - так что просто не делайте этого: :)
Плюс классимя вводит в заблуждение, так как это не Thread
, а Runnable
.Называть это что-то вроде PhysicsTask
или PhysicsSimulationRun
, возможно, было бы более понятным.)