【问题标题】:kill the deadlock杀死僵局
【发布时间】:2011-10-15 18:35:51
【问题描述】:

我目前正在(尝试)编写一个小游戏。我有一个小的设计/死锁问题。

当我按下一个按钮时,一个新的 Intent 会打开,surfaceDestroyed 设置一个布尔值来设置线程休眠。 当我返回时,线程会收到通知信号。

这在大约 90% 的时间内有效(当我使用 eclipse 调试时为 100%)。

我相信死锁发生在线程的运行函数中(两个同步)。问题是,wait() 需要一个同步的线程,而 ondraw() 需要在 surfaceholder 上的锁。

我已经玩了一点,但所有其他组合都让一切变得更糟,我不知道如何解决这个问题。所以请帮忙:)

主题:

class BattleEarthThread extends Thread {
    private SurfaceHolder _surfaceHolder;
    private BattleEarthView _battleEarthView;
    private boolean _run = false;
    private boolean _suspended = false;

    public SurfaceHolder getSurfaceHolder() {
        return _surfaceHolder;
    }

    public BattleEarthThread(SurfaceHolder surfaceHolder, BattleEarthView panel) {
        _surfaceHolder = surfaceHolder;
        _battleEarthView = panel;
    }

    public void setRunning(boolean run) {
        _run = run;
    }

    public void setSuspend(boolean suspend) {
        _suspended = suspend;
    }

    public boolean getSuspended() {
        return _run;
    }

    public boolean getRunning() {
        return _run;
    }

    @Override
    public void start() {
        super.start();
        _run = true;
    }

    @Override
    public void run() {
        Canvas c;
        while (_run) {
            c = null;
            try {
                synchronized(this)
                {
                        c = _surfaceHolder.lockCanvas(null);
                        synchronized (_surfaceHolder) {

                            if(_suspended)
                                this.wait();

                            else {
                                _battleEarthView.onDraw(c);
                            }
                        }
                    }
            } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                if (c != null) {
                    _surfaceHolder.unlockCanvasAndPost(c);
                }
            }
        }
    }
}

【问题讨论】:

  • 我们需要查看其他线程的代码才能完全理解这一点。

标签: java android multithreading deadlock


【解决方案1】:

这就是问题所在:

synchronized(this) {
    c = _surfaceHolder.lockCanvas(null);
    synchronized (_surfaceHolder) {

        if(_suspended)
            this.wait();

        else {
            _battleEarthView.onDraw(c);
        }
    }
}

您要取出两把锁 - this_surfaceHolder。然后,您通过调用wait...释放this 上的锁...但您仍然拥有_surfaceHolder 上的锁。

现在假设另一个线程在同一个对象上执行相同的代码。它设法获得了this 的锁,因为目前没有其他人拥有它……但是在尝试获得_surfaceHolder 时它会阻塞,因为等待线程拥有它。

此时,您已经吃饱了:

  • 没有线程可以获取正在等待的对象上的锁,因为第二个线程拥有它
  • 即使另一个线程可以对该锁进行脉冲处理,等待的线程仍然需要在继续之前重新获取this 上的锁,这是它无法做到的

所以基本上你有两个线程,每个线程都拥有一个锁并等待不可能发生的事情。这不是相当普通的死锁(每个线程拥有一个锁并等待另一个锁),但它非常接近。

道德:不要在当前“拥有”比将要调用wait() 的监视器更多的线程上调用wait()

【讨论】:

  • 我是这么认为的,但是如何解决这个问题呢? notify 需要线程锁,ondraw 需要surfaceholder?
  • @user989349:说实话,你还不清楚你想要实现什么。但是 eek - 我没有看到您锁定了 thread 引用。首先,不要扩展 Thread - 而是实现 Runnable。其次,不要获取线程上的锁或等待它。其他事情会这样做,所以最好不要自己做。是什么在触发锁,它可以改为脉冲_surfaceHolder 吗?
  • 澄清一下:我有一张地图,当我点击一个城镇时,我想建造一些东西。当我离开城镇时,应该再次显示地图。所以地图绘制的第一部分来自 LunarLander(还有一个线程),第二部分来自 Oracle(搜索 threadPrimitiveDeprecation :))
  • @user989349:恐怕这并没有说明太多——“第二部分来自 Oracle”是什么意思?
  • 抱歉第一次在stackoverflow上写东西,这里编辑了这么多。好吧,当我不需要它时,我不希望线程绘制地图。我想阻止线程绘制。于是我搜索了线程停止,发现:download.oracle.com/javase/1.4.2/docs/guide/misc/…
猜你喜欢
  • 2013-06-01
  • 2011-09-26
  • 2011-09-14
  • 2014-06-19
  • 1970-01-01
  • 1970-01-01
  • 2011-04-29
  • 2015-04-12
  • 1970-01-01
相关资源
最近更新 更多