1

好的,我确定我在这里遗漏了一些简单的东西,但看不到它。我正在使用一个标志来结束一个线程,然后加入它以整齐地清理,但连接永远不会完成它只是被卡住等待。当前线程的运行循环中没有任何内容,因此它不会卡在单独的循环中。

线:

package com.nox.willywars;

public class GameThread extends Thread {

//{{Variables
private boolean running;
//}}

//{{Getters/Setters
public void setRunning(boolean running) {
    this.running = running;
}
//}}

//{{Constructor
public GameThread() {
    running = false;
}
//}}Constructor

//{{Public methods
@Override
public void run() {
    while(running) {
        ///...CODE GO HERE
    }
}

public boolean isRunning() {
    return running;
}
//}}
}

无法阻止它的代码:

//{{Lifecycle methods
@Override
public void create() {
    //LOAD! Probably debug temp
    TileFactory.load();

    mapScreen = new MapScreen();
    setScreen(mapScreen);

    gameThread = new GameThread();
    gameThread.setRunning(true);
    gameThread.start();
}

@Override
public void resize(int width, int height) {
}

@Override
public void pause() {
    killGameThread();
}

private void killGameThread() {
    if(gameThread != null) {
        if(gameThread.isAlive() && gameThread.isRunning()) {
            gameThread.setRunning(false);
            boolean retry = true;
            while(retry) {
                try {
                    gameThread.interrupt();
                    gameThread.join();
                    retry = false;
                } catch (InterruptedException e) {}
            }
        }
    gameThread = null;
    }
}
//}}

目前它到达 gameThread.join() 并卡在那里,等待线程完成。我在这里错过了什么吗?据我了解,一旦 running 设置为 false,线程应该完成,然后加入应该正常发生,因为它已经停止。

编辑:从运行 GameThread 的类中添加了更多代码。Pause() 是执行 KillGameThread 的地方。我已经让运行变得不稳定,但它没有任何效果。我还发现了另一个奇怪的症状:有人建议在 GameThread 卡住的时候查看里面的内容,所以我进入了调试器。当 join() 被卡住时,我暂停了 GameThread 线程并看到它在 while(running) 上运行,并且运行肯定是错误的。然后,当我跳过代码时,它退出了循环并正确完成,这似乎是由我的调试引起的。好像线程以某种方式挂起?

4

3 回答 3

3

首先将运行标志设置为 volatile

private volatile boolean running;

游戏线程到底在做什么,可能它被某些 I/O 操作阻塞了。
如果游戏线程没有休眠/等待/加入,那么中断它是没有用的。
您需要共享游戏线程代码。

于 2013-10-28T09:38:30.853 回答
1

正如user2511414 指出的那样,尝试使用 using volatile。简而言之,这将确保值 odrunning始终被直接访问而不是缓存。

它设置volatile不会解决这种情况,他的问题很可能GameThread#run在于您注释掉的方法的代码部分。

您可以尝试使用jstackjvisualvm获取您尝试加入的线程的线程转储。这至少会告诉你它挂在哪里,并可能引导你找到解决方案。

于 2013-10-28T09:37:59.517 回答
1

running标志未正确同步。这可能(理论上)导致线程没有注意到状态变化……由于 Java 内存模型的工作方式。您应该将其声明为volatile或始终在同步方法调用(或同步块)中访问和更新它。

但是(IMO)真正的问题在于您告诉线程停止的方式(实际上是方式),并且线程正在检查或响应。

  • 如果你打算使用一个标志来告诉线程停止,那么线程需要经常检查那个标志。如果线程可以在检查之间花费无限长的时间做其他事情,那么它可能永远不会注意到它需要停止。

  • 如果你打算使用Thread.interrupt()那么:

    • 您的代码应该调用Thread.isInterrupted()以测试线程的“中断”状态,而不是临时标志。此外,它应该定期测试状态。

    • 您的代码需要确保它正确处理InterruptedExceptionInterruptedIOException。这一直适用于调用堆栈。

请注意,在大多数情况下,调用实际上Thread.interrupt()并不会中断线程。在大多数情况下,它只是设置一个需要手动测试的标志。您获得的唯一情况是在某些阻塞调用中;例如和一些 IO 调用。Object.wait(...)


你已经遗漏了大部分应该发生这些事情的代码。我们能说的最好的就是问题很可能出在您没有向我们展示的代码中。

于 2013-10-28T10:00:18.493 回答