即使其他线程未持有锁,也要等待同步对象

时间:2012-02-25 20:08:03

标签: android synchronization ontouchevent

我正在开发一款Android游戏并且有一个奇怪的问题,偶尔游戏会在很长一段时间内无法响应,然后才能恢复生机。据我所知,这种暂停,如果它发生,只会在游戏启动时发生。一旦正常运行,游戏似乎就会表现出来。

经过一些调查后,似乎onTouchEvent回调被阻止,试图获取与游戏线程共享的同步对象的锁定。同时游戏线程正常运行,并且不会长时间锁定同步对象。

我的理解是,一旦游戏线程释放了锁,doTouchEvent中的synchronized块就会获得对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;
}

}

2 个答案:

答案 0 :(得分:1)

似乎这个问题归结于同步不能保证在等待线程获取锁定的顺序时的公平性。实际上,如果另一个cpu密集型线程重复获取并释放锁,则线程可以无限期地等待锁定。

请参阅此主题讨论完全相同的问题......

http://groups.google.com/group/android-developers/browse_frm/thread/ffe76e4a433c8675/f424fb7dc3baeb10

...这里是一个线程安全但无同步的解决方案的例子。

http://blog.tomgibara.com/post/208684592/avoiding-starvation

在遇到上述情况之前,我改变了我的代码,使用ConcurrentLinkedQueue在线程之间传递运动事件,这在消除停顿方面似乎也很有效。

答案 1 :(得分:0)

..你在游戏循环的每个循环中获得3个不同的锁!你必须考虑一个更好的设计,你不需要锁。这将使您的游戏性能陷入困境。