优雅地中断java线程

发布于 2025-01-02 12:31:32 字数 1458 浏览 2 评论 0原文

我写了一个 Java ME 益智游戏。我这样编写了代码:有一个线程在应用程序启动时启动,并且一旦游戏开始,就会有第二个线程在无限循环中运行 - 主游戏循环。第二条线索一度看起来像这样:

public void run() {
    init();
    while (shouldIRun) {            
        updateGameState();
        checkUserInput();
        updateGameScreen(getGraphics());
        this.flushGraphics();         
    }
}

可爱。这个线程一直在运行,直到我想杀死它,当我将布尔值 shouldIRun 设置为 false 时,它​​就会优雅地退出。

但后来我意识到我想要更多。该游戏是一款益智游戏,玩家有可能做出错误的动作,然后陷入困境。发生这种情况时,他们可以启动一个表单并选择“重新启动级别”选项。然后设置标志 restartLevel,当无限循环到达 updateGameState() 方法时,关卡将重新启动。但这对我来说有点像一场赌博——我不想在出现并发问题时开始更改主循环中使用的对象的变量,尽管我可能很偏执。在实践中,我意识到我想要做的事情非常明确:我只是想暂停无限循环线程,将变量更改为我想要的,然后重新启动。

我是通过以下方式做到这一点的:

public void run() {
    init();
    while (shouldIRun) {            

        if (shouldIWait) {
            iAmWaiting=true;
            while (shouldIWait) { };
            iAmWaiting=false;
        }

        updateGameState();
        checkUserInput();
        updateGameScreen(getGraphics());
        this.flushGraphics();
    }
}

我的想法如下。如果我现在想从“基本”线程“暂停”第二个线程,我只需将 shouldIWait 变量设置为 true,然后循环直到我注意到 iAmWaiting 变量也是如此。我现在可以肯定地知道第二个线程已经暂停,并且我确切地知道它在哪里暂停,“暂停”实际上是指“暂时陷入无限循环”。我现在可以闲逛一些基本变量,重新启动关卡,并大致解决问题,然后最后将 shouldIWait 设置回 false,然后我们再次开始。

我的问题是:这对我来说效果很好,但有点像拼凑。是否有一些完全标准的方法来完成可能是常见的事情 - 在给定点暂停线程,然后在我准备好时重新启动它,这样更好比我在做什么?我特别怀疑“将 java 放入无限循环”可能不是一件聪明的事情。

I have written a Java ME puzzle game. I have written the code thus: there is a thread that starts when the app starts, and, once the game has got going, there's a second thread that just runs in an infinite loop -- the main game loop. The second thread looked like this, at one point:

public void run() {
    init();
    while (shouldIRun) {            
        updateGameState();
        checkUserInput();
        updateGameScreen(getGraphics());
        this.flushGraphics();         
    }
}

Lovely. This thread just runs and runs, until I want to kill it, when I just set the boolean shouldIRun to false, whereupon it exits gracefully.

But later on I realised I wanted more. The game is a puzzle game and it's possible for the player to make the wrong moves and then get stuck. When this happens they can fire up a form and select the "restart level" option. A flag restartLevel then gets set, and when the infinite loop gets to the updateGameState() method the level is restarted. But this feels to me like a bit of a gamble -- I don't want to start changing variables of objects being used in the main loop in case of concurrency issues, although I'm probably being paranoid. In practice what I realised I wanted to do was very clear: I simply wanted to pause the infinite loop thread, change the variables to what I wanted, and then restart.

I have done this in the following way:

public void run() {
    init();
    while (shouldIRun) {            

        if (shouldIWait) {
            iAmWaiting=true;
            while (shouldIWait) { };
            iAmWaiting=false;
        }

        updateGameState();
        checkUserInput();
        updateGameScreen(getGraphics());
        this.flushGraphics();
    }
}

What I am thinking is the following. If I now want to "pause" this second thread, from the "base" thread, I just set the shouldIWait variable to true, and then just loop until I notice the iAmWaiting variable is also true. I now know for sure that the second thread has paused and I know precisely where it has paused, where by "paused" I actually mean "is stuck in an infinite loop for the time being". I can now goof around with some essential variables, restart the level, and generally sort things out, and then finally set shouldIWait back to false and off we go again.

My question is this: this works fine, for me, but smacks of being a kludge. Is there some completely standard way of doing what is presumably a common thing -- pausing a thread at a given point and then restarting it when I'm ready, which is better than what I'm doing? In particular I suspect that "putting java into an infinite loop" is perhaps not a clever thing to do.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

屋顶上的小猫咪 2025-01-09 12:31:32

通常,这就是您使用 Object.wait()Object.notify() 的用途。

有几种方法可以根据您的情况实现它,但这里有一个简单的示例:

Object monitor = new Object();
volatile boolean done = false, wait = false;

/* Running on one thread: */
public void run() {
    synchronized(monitor) {
        while(!done) {
            while(wait) {
                monitor.wait();
            }
            gameLogicAndStuff();
        }
    }
}

/* Running on another thread: */
public void showResetForm() {
    wait = true;
    synchronized(monitor) {
        actuallyShowResetForm();
        wait = false;
        monitor.notifyAll();
    }
}

Normally, this is what you would use Object.wait() and Object.notify() for.

There are a couple of ways to implement it for your situation, but here's a simple example:

Object monitor = new Object();
volatile boolean done = false, wait = false;

/* Running on one thread: */
public void run() {
    synchronized(monitor) {
        while(!done) {
            while(wait) {
                monitor.wait();
            }
            gameLogicAndStuff();
        }
    }
}

/* Running on another thread: */
public void showResetForm() {
    wait = true;
    synchronized(monitor) {
        actuallyShowResetForm();
        wait = false;
        monitor.notifyAll();
    }
}
七婞 2025-01-09 12:31:32

也许终止线程并使用新级别启动一个新线程会更简单。

如果有一些信息需要从一个级别传递到下一个级别,也许您可​​以重构代码,以便首先收集一些一般信息,然后为每个级别启动一个线程。 (通过启动线程,我的意思是使用线程池。)

我不认为您当前正在忙等待所做的事情是邪恶的。正如 Ben Flynn 在评论中提到的,您可以通过循环 Thread.sleep(50) 使其处于半忙等待状态。

Maybe it would just be simpler to kill the thread and start a new one with the new level.

If there is some information that needs to be carried from one level to the next, maybe you could refactor your code such that you gather some general information first and then start a thread for each level. (And by starting a thread, I mean using a thread pool.)

I don't think what you are currently doing with busy waiting is evil. As Ben Flynn mentioned in the comments, you could make it semi-busy waiting by looping over Thread.sleep(50).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文