简体   繁体   中英

Run thread in background in java

I'm writing a chess program in java. So far things are coming along fine but I do have a problem with updating my UI.

Here's a snippet of code from class ChessBoard which extends JPanel. This is called when a user tries to make a move:

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
}

The thread is calling "run" on my instance of ChessBoard. The algorithm that finds the move can take several seconds to decide on a move.

I would like for my UI to update to reflect the user's move and then run the algorithm. That's why I run the algorithm on a separate thread. But my UI is not being updated until the computer also makes a move.

So if the user clicks a space to send a piece there, the screen freezes and then all of a sudden the piece has moved but the computer has moved also and it is again the player's turn.

Any help will be greatly appreciated.

thread.run() is going to execute the code in the thread's run method on the current thread. You want thread.start() .

Relevant JavaDoc

The repaint method doesn't actually repaint immediately. It basically tells the JPanel that it ought to repaint itself soon. Then you go ahead on the same thread and calculate the AI's move, which will freeze the window because Swing isn't multi-threaded.

First, threads are not re-entrant (I'll explain that in a moment).

thread.run() is not causing the thread to execute in a separate thread, it's just call the run method of the thread (within the current Thread s context.

What you need to do is set up a condition loop within your Thread that you can trigger in order to execute the logic you need.

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...
        }
    }
}

Now, Thread s are non-reentrant, this means that once the run method has complete, that instance of the Thread can not be restarted.

Hence using thread.start() more then once will not work (can't remember if it throws an exception or not) (hence the reason I prefer Runnable )

So. What you want to do, is start the Thread when your program loads and when you need to, call thread.doNextMove() to cause it calculate the what ever it is you need.

Now, also remember, Swing is not Thread safe. That is, you should NEVER update the UI from any Thread other than the Event Dispatching Thread (or EDT)

You might also want to have a read through Concurrency in Swing

Oh and Concurrency in Java

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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