【问题标题】:Run thread in background in java在java中后台运行线程
【发布时间】:2012-08-30 01:21:16
【问题描述】:

我正在用 java 编写一个国际象棋程序。到目前为止一切都很好,但我在更新我的 UI 时确实遇到了问题。

这是来自 ChessBoard 类的代码的 sn-p,它扩展了 JPanel。当用户尝试移动时调用它:

if ( isLegalMove( aMove ) ) { // If the move's legal
    makeMove( aMove ); // Make that move
    select = null; // Reset some info
    drag = null;
    toggleTurn(); // Change turns
    generateMoves( 0 ); // Get legal moves for CPU
    repaint(); // Redraw board
    thread.run(); // Run chess algorithm
}

线程正在我的 ChessBoard 实例上调用“运行”。找到移动的算法可能需要几秒钟来决定移动。

我希望我的 UI 更新以反映用户的移动,然后运行算法。这就是我在单独的线程上运行算法的原因。但是我的用户界面在计算机也采取行动之前不会更新。

因此,如果用户单击空间将棋子发送到那里,屏幕会冻结,然后棋子突然移动了,但计算机也移动了,又轮到玩家了。

任何帮助将不胜感激。

【问题讨论】:

  • 你确定运行时间长的代码在线程中吗?还是在generateMoves(0)?使用调试器只需几秒钟即可找出答案。

标签: java multithreading user-interface background chess


【解决方案1】:

thread.run() 将在当前线程上执行线程的 run 方法中的代码。你想要thread.start()

Relevant JavaDoc

repaint 方法实际上不会立即重新绘制。它基本上告诉 JPanel 它应该很快重新绘制自己。然后在同一个线程上继续计算 AI 的移动,这将冻结窗口,因为 Swing 不是多线程的。

【讨论】:

  • 我认为您可能想重新考虑该答案(从 OP 的 sn-p 的上下文中)。来自Java Docs多次启动一个线程是不合法的。特别是一个线程一旦完成执行就不能重新启动
  • @MadProgrammer 虽然你说的是有效的,但 1)作为 OP 的主要问题的“停止”行为正是由 run() 方法引起的,2)来自代码 sn-p我们不知道 OP 是否正在重用线程实例。 OP 可能正在实例化 if 块之外的线程
  • @MadProgrammer 正如 Adrian 所说,根据他的代码,这里唯一可以保证的问题是他调用了错误的方法。我将他链接到的 JavaDoc 部分明确指出,您不能多次启动线程,所以如果他阅读答案,他也会弄清楚那部分。
  • @Chris 所以,我们现在正在跟踪 OP 的路径,而不是一个新问题,很好:D
【解决方案2】:

首先,线程不能重入(我稍后会解释)。

thread.run() 不会导致线程在单独的线程中执行,它只是调用线程的run 方法(在当前Threads 上下文中。

您需要做的是在您的Thread 中设置一个条件循环,您可以触发它以执行您需要的逻辑。

public class ChessThread extends Thread { // I prefer Runnable, that's me
    protected static final Object NEXT_MOVE_LOCK = Object();

    public ChessThread() {
        setDaemon(true); // This will allow the JVM to exit without the need to terminate the thread...
    }

    public void doNextMove() {
        // Notify the "wait" that we want to continue calculating the next move
        synchronized (NEXT_MOVE_LOCK) {
            NEXT_MOVE_LOCK.notify();
        }
    }       

    public void run() { 
        while (true) {
            // Wait for the "next move" request
            synchronized (NEXT_MOVE_LOCK) {
                try {
                    NEXT_MOVE_LOCK.wait();
                } catch (InterruptedException exp) {
                }
            }
            // Calculate the next move...
        }
    }
}

现在,Threads 是不可重入的,这意味着一旦 run 方法完成,Thread 的实例就无法重新启动。

因此多次使用thread.start() 将不起作用(不记得它是否引发异常)(因此我更喜欢Runnable

所以。您想要做的是在程序加载时启动Thread,当您需要时,调用thread.doNextMove() 以使其计算出您需要的任何内容。

现在,还要记住,Swing 不是 Thread 安全的。也就是说,除了Event Dispatching Thread(或 EDT)之外,您永远不应该从任何 Thread 更新 UI

您可能还想阅读Concurrency in Swing

哦还有Concurrency in Java

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多