繁体   English   中英

摆脱潜在的僵局

[英]Getting out of a potential deadlock

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

  • 无法关闭视窗
  • 如果没有IDE上的“终止”按钮,则无法终止
  • 空白,没有任何反应,完全没有异常或错误。

如果这些事情陷入僵局,那么我大概已经解决了一半的问题。 我知道有两个正在运行的线程: AWT-EventQueue-0frameThread

这使用的是我构建的自定义库,但尚未完全开发(您可以称其为alpha-beta阶段?)。 我决定用它来制作Pong游戏。 实际上,我的导师为我分配了游戏。 我将使用它的库。

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

我想指出, 根据oracle教程内在锁指出:

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

在执行此操作之前,我已经完成了一个同步块,以从我在程序中知道的唯一具有锁的线程中获取锁。 失败。 因此,我使该方法同步,并且发生了上面列出的要点。

我的代码是

// 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);
}

如果那没有帮助,您可以尝试浏览我的代码...

我的Pong游戏代码存储库

我最好的选择是我为延迟该方法所做的事情有问题。 我想做的是为每个对象设置一个固定的“ x” hertz更新率。 be easier if it was a return type method (not void). 如果它是一个返回类型方法(不是void), 更容易。

您声明:

我的图书馆使用了Swing组件,我怀疑这与它有什么关系

我担心你可能是错的。 您似乎通过while循环完全阻塞了Swing事件分配线程(EDT),并且由于该线程负责所有Swing图形和用户交互,因此将有效地冻结GUI。

  • 而不是会阻塞EDT的while (true)循环,而是使用Swing计时器。
  • 不要暂停您的图形绘制,因为这会使您的程序响应性差。
  • 不要从绘画方法中调用同步。
  • 不要在诸如paintComponent之类的绘画方法中更改对象的状态(即,不要从paintComponent中调用您的updateGame()方法)。 这是因为您永远无法完全控制是否调用此方法。 JVM可以响应操作系统清除干净区域的请求而将其从您的控制之外调用,并且如果重新绘制请求不断堆积,JVM可能会忽略您的重新绘制请求。

这似乎是一个僵局,并且无疑与Swing的使用有关。 整个应用程序挂起的症状通常是由事件分发线程(EDT)死锁引起的。

问题似乎出在您的Ball.java类中的以下代码中:

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

似乎hertz字段未显式初始化,因此其默认值为0L 用于wait(timeout)方法的值为零将无限期阻塞,即它将等待而没有超时。 似乎没有通知该对象,因此此方法将永远挂起调用线程。 此方法是从JPanel.paintComponent调用的JPanel.paintComponent方法调用的,因此这冻结了应用程序的用户界面。

不要试图通过在绘画例程中睡觉或暂停来控制更新速率。 绘制例程应该总是做尽可能少的工作,检查模型的当前状态并发出适当的图形调用,并尽快返回。

您的程序是多线程的,因此您将需要同步对象。 线程管理器线程正在更新游戏对象,而EDT正在使用游戏对象绘画。 对对象的访问将在多个线程上进行,因此需要同步。 同步的块(或方法)应尽可能少地做:进入,更新(或绘制)并离开。 EDT上的代码永远不要调用wait因为这可能会导致重涂性能和响应速度变差。 更新线程应该在锁之外进行尽可能多的计算,并在保持锁的同时简单地用新值更新游戏对象。 这将使EDT在重涂周期中被阻止获取锁的时间最小化。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM