摆脱潜在的僵局

时间:2014-07-13 03:46:56

标签: java multithreading swing

我遇到了SEEM会陷入僵局的事情。死锁听起来有点像:

  • 无法关闭窗口
  • 无法在IDE上终止按钮终止
  • 空白且没有任何反应,根本没有例外或错误。
如果那些是发生在死锁中的事情,那么我可能已经解决了一半问题。我知道有两个线程正在运行:AWT-EventQueue-0frameThread

这是使用我构建的自定义库,但尚未完全开发(您可能称之为alpha-beta阶段?)。我决定用它做一个Pong游戏。实际上我的导师给了我这个游戏。我只是想用它来使用我的库。

我的库使用Swing组件,我怀疑它与它有什么关系。

我想指出intrinsic locks according to the oracle tutorials状态

  

“当线程调用synchronized方法时,它会自动获取该方法对象的内部锁定,并在方法返回时释放它。即使返回是由未捕获的异常引起的,也会发生锁定释放。”

在做这个说法之前,我已经完成了一个synchronized块,从我在程序中知道的唯一一个可以锁定的线程获取锁。失败。所以我使方法同步,并且,上面列出的要点发生了。

我的代码是

// Threads
static ThreadManager tm = new ThreadManager() {

    @Override
    protected void runFrameThread() {//ThreadManager has threads in it that you can start.
        while (true) {               //These are just the abstract inherited methods the
            Main.jpane.repaint();    // threads inside the manager call
        }
    }

    @Override
    protected void runMathThread() {
    }

    @Override
    protected void runIntenseMathThread() {
    }

};

// set frame rate
static {
    tm.setFPS(30L);
}
public synchronized void draw(Graphics g) {// main problem: synchronized method here.
    try {
        wait(hertz);
    } catch (InterruptedException e) {
        System.err.println("ERROR: " + e.getLocalizedMessage());
        e.printStackTrace();
    }
    g.setColor(rgb);
    g.fillRect(this.x, this.y, width, height);
}

如果这没有帮助,您可以尝试查看我的代码......

My Code Repository for the Pong game

我最好的选择是我做了什么来推迟这个方法的错误。我想要做的是以'x'hertz的设定速率为每个对象提供更新率。如果它是返回类型方法(非空),它会更容易。

2 个答案:

答案 0 :(得分:3)

你说:

  

我的库使用Swing组件,我怀疑它与它有什么关系

我担心你可能会错。您似乎使用while循环完全阻止了Swing事件调度线程(EDT),并且由于此线程负责所有Swing图形和用户交互,因此这将有效地冻结您的GUI。

  • 而不是阻止EDT的while (true)循环,而是使用Swing Timer。
  • 不要暂停你的图形绘图,因为这会让你的程序看起来反应不佳。
  • 不要在绘画方法中调用同步。
  • 不要在绘图方法中更改对象的状态,例如paintComponent(即,不要在paintComponent中调用updateGame()方法)。这是因为您永远无法完全控制是否调用此方法。它可以由JVM调用,以响应操作系统清除脏区域的请求,如果重新绘制请求正在堆叠,JVM可能会忽略您的重绘请求。

答案 1 :(得分:2)

这似乎是一个死锁,它肯定与使用Swing有关。整个应用程序挂起的症状通常是由事件派发线程(EDT)死锁引起的。

问题似乎出现在此代码中,该代码位于Ball.java类:

public synchronized void draw(Graphics g) {
    try {
        wait(hertz);
    } catch (InterruptedException e) {
    ...
}

hertz字段似乎未显式初始化,因此其默认值为0Lwait(timeout)方法的值为零将无限期地阻塞,也就是说,它将等待没有超时。它似乎不会被通知此对象,因此此方法将永久挂起调用线程。此方法是从JPanel.paintComponent方法调用的,该方法由EDT调用,因此冻结了应用程序的用户界面。

不要试图通过在绘画程序中休眠或暂停来控制更新率。绘图程序应始终尽可能少地工作,检查模型的当前状态并发出适当的图形调用,并尽快返回。

您的程序是多线程的,因此您需要同步对象。线程管理器线程正在更新游戏对象,EDT正在使用游戏对象进行绘制。 在多个线程上将访问您的对象,因此需要同步。同步块(或方法)应该尽可能少:进入,更新(或绘制),然后离开。 EDT上的代码永远不应该调用wait,因为这可能会导致重复性能和响应能力下降。更新线程应该在锁之外执行尽可能多的计算,并且只需在保持锁定时使用新值更新游戏对象。这将最小化在重绘周期期间EDT被阻止获取锁定的时间量。