Я разрабатываю игру для Android, и у меня возникла странная проблема, из-за которой иногда игра перестает отвечать на запросы в течение длительного периода времени, прежде чем вернуться к жизни. Насколько я могу судить, эта пауза если и возникает, то только при запуске игры. После нормального запуска игра, кажется, ведет себя сама.
После некоторого расследования выяснилось, что обратный вызов onTouchEvent блокируется при попытке получить блокировку объекта синхронизации, который он разделяет с игровым потоком. Тем временем игровой поток работает нормально и не удерживает блокировку объекта синхронизации в течение длительного периода времени.
Насколько я понимаю, синхронизированный блок в doTouchEvent получит блокировку mSyncObject, как только эта блокировка будет снята игровым потоком. Но в некоторых случаях кажется, что игровой поток может получить и снять блокировку несколько сотен раз, прежде чем doTouchEvent в конечном итоге сможет получить свою блокировку.
Нет другого кода, использующего тот же объект для синхронизации.
Я скопировал соответствующие фрагменты кода ниже. Из того, что я могу понять, он не делает ничего необычного, поэтому я несколько сбит с толку странным поведением, которое я наблюдаю.
Был бы признателен за любую помощь в этом. Заранее спасибо!
class GameThread extends Thread {
// ...some methods and members omitted...
private volatile int mFrameCount = 0;
private Object mSyncObject = new Object();
@Override
public void run() {
while (!mShutDown) {
Canvas canvas = null;
long timestampA = System.currentTimeMillis();
try {
synchronized (mSurfaceHolder) {
canvas = mSurfaceHolder.lockCanvas(null);
// Synchronized on our object...
synchronized (mSyncObject) {
long now = System.currentTimeMillis();
if ((now > mLastTime) && !mPaused) {
double timestep = (double) (now - mLastTime) / 1000.0;
mGame.update(timestep);
}
mLastTime = now;
if (canvas != null) {
mGame.draw(canvas);
}
}
}
} finally {
if (canvas != null) {
mSurfaceHolder.unlockCanvasAndPost(canvas);
}
}
// have tried inserting a sleep() here, but it didn’t help
++mFrameCount;
}
}
// Called from the UI thread
public boolean doTouchEvent(MotionEvent event) {
boolean result = false;
// Synchronized on our object...
// The game loop in run() acquires and releases a lock
// on this object on every frame, so would expect to be
// blocked here for no longer than one frame.
// However, on occasions have been blocked here for over
// 2000 iterations of the game loop.
int frameCount = mFrameCount;
synchronized (mSyncObject) {
int framesWaited = mFrameCount - frameCount;
if (framesWaited > 1) {
Log.i("Block", "doTouchEvent waited " + framesWaited + " frames for lock");
}
if (!(mPaused || mShutDown)) {
result = mGame.doTouchEvent(event);
}
}
return result;
}
}