Java线程不会加入

时间:2013-10-28 09:31:38

标签: java

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

主题:

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()并被卡在那里,等待线程完成。我在这里错过了什么吗?据我所知,一旦运行设置为false,线程应该完成,然后加入应该正常发生,因为它已经停止。

编辑:从运行GameThread的类中添加了一些代码。 Pause()是执行KillGameThread的地方。我已经使运行变得不稳定但它没有效果。 我发现了另一个奇怪的症状:有些人建议在GameThread卡住时看看里面是什么,所以我进入了调试器。当join()被卡住时,我暂停了GameThread线程并看到它在运行时运行,并且运行肯定是假的。然后,当我跨过代码时,它退出循环并正确完成,看起来是由我的调试引起的。这就好像线程被某种方式暂停了?

3 个答案:

答案 0 :(得分:3)

首先将运行标志设置为易失性

private volatile boolean running;

游戏线程究竟做了什么,也许它被某些I / O操作阻止了 如果游戏线程没有睡眠/等待/加入,那么打断它就没用了 你需要分享游戏线程代码。

答案 1 :(得分:1)

作为user2511414 pointed out,请尝试使用volatile。简而言之,这将确保始终直接访问值running而不是缓存。

设置volatile无法解决问题,他的问题很可能出现在您注释掉的GameThread#run方法的代码部分。

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

答案 2 :(得分:1)

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

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

  • 如果您要使用标志告诉线程停止,那么线程需要经常检查该标志 。如果线程可能花费无限长的时间在检查之间做别的,那么它可能永远不会注意到它需要停止。

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

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

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

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


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