0

I am writing a GUI game, and I want to wait for the game to finish, before returning the winner. However, since my Game manager class is separate from the class used to implement the game logic and detect a win, I want to know how I can make the game manager wait until the other class notifies it of a win, and then proceed to do other stuff. I have not really worked much with multithreading before, so I'm hoping someone could explain how I might achieve this.
Here is some relevant code from the GameManager class' main that I've tried:

...
Game game = new Game(mode);
String winner = game.getWinner();
...

And from the Game class:

public Game(Game.Mode mode){
    this.board = new Board(7);
    window = new BoardFrame(7, 7, mode, board); //Graphical interface
    window.setVisible(true);
}

public String getWinner(){
    synchronized(board.WINNER){
        try {
            board.WINNER.wait();
        } catch (InterruptedException e) {}
    }
    return board.WINNER;
}

And the Board class:

public boolean update(int num){

    if (isValidMove(CurrentPlayer, num)){
        buttonClients.get(positions.get(CurrentPlayer)).clear();

        positions.put(CurrentPlayer, num);
        board[num] = 1;
        buttonClients.get(num).performCallback(CurrentPlayer);

        if ((WINNER = isGameFinished())!=""){
            //Disable all further inputs
            for (int i = 0; i<board.length; i++){
                board[i] = 1;
            }
            synchronized (WINNER) {
                WINNER.notify();
            }                                   
        }

        CurrentPlayer = (CurrentPlayer==PLAYER1)?PLAYER2:PLAYER1;
        return true;        
    }
    return false;
}

EDIT: So I have found the cause of the screen display issue, which is that all my code for the GameManager was in an EventQueue.invokeLater() block. I have taken it out of that block for now, and the screen is displaying properly now. However, when I play until the end, and the synchronized(WINNER) block is finally run, it seems like nothing happens? In other words, the game continues waiting on WINNER.

b_pcakes
  • 2,452
  • 3
  • 28
  • 45

2 Answers2

1

When I'm waiting on a thread, my favorite is using a CountDownLatch and Maybe using a Callable<V> and submitting it to a thread executor which returns a Future<V> which blocks until the thread is done.

public class Example {
    ExecutorService executorService = Executors.newCachedThreadPool();
    public void init(){
        CountDownLatch latch = new CountDownLatch(1);
        Future<Boolean> submit = executorService.submit(new Thread3());
        executorService.execute(new Thread1(latch, submit));
        executorService.execute(new Thread2(latch));
    }

    public class Thread1 implements Runnable{
        private CountDownLatch latch;
        private Future<Boolean> thread3;
        public Thread1(CountDownLatch latch, Future<Boolean> thread3) {
            this.latch = latch;
            this.thread3 = thread3;
        }

        @Override
        public void run() {
            int i = 0;
            try {
                thread3.get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
            while (i < 50){
                LockSupport.parkNanos(1000);
                i++;
            }
            latch.countDown();
        }
    }

    public class Thread2 implements Runnable{
        private CountDownLatch latch;

        public Thread2(CountDownLatch latch) {
            this.latch = latch;
        }

        @Override
        public void run() {
            try {
                latch.await();
                System.out.println("We can continue");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }

    public class Thread3 implements Callable<Boolean>{

        @Override
        public Boolean call() throws Exception {
            int i = 0;
            while (i < 50){
                LockSupport.parkNanos(1000);
                i++;
            }
            return true;
        }
    }

}

Good Resource: http://tutorials.jenkov.com/java-concurrency/index.html

John
  • 315
  • 2
  • 7
0

There's a couple of ways you could do this, but by far the neatest will be to use the observer pattern to create an event listener. The idea behind this pattern is to allow code to register an action to be performed when an event occurs, while isolating the event handler from the action it's going to invoke. Note that this solution doesn't require any multithreading.

If you really do want your GUI and game logic running on separate threads, seems like you're trying to implement the locking approach described here. There's a couple of things to watch out for:

  • The JVM can give you a waiting thread an InterruptedException at any time, for any reason. You should always check the condition that caused you to wait before you proceed.
  • Any time you're accessing state shared across threads, you need to make sure you are using synchronized and volatile appropriately.
  • Where you lock on WINNER, bear in mind this field can change. If Board is locked on WINNER and changes its value, a new thread entering Game would be free to obtain its lock before the Board block completes, because they're locking on different objects.
Community
  • 1
  • 1
hugh
  • 2,237
  • 1
  • 12
  • 25
  • Is my threading approach different from the one described at the link you provided? It looks to me that they are the same format? Yet for some reason when I try to do this, the gui freezes with a blank screen – b_pcakes Oct 17 '15 at 09:53
  • It looks like you're using the same approach, but it would be difficult to say more without the code for `BoardFrame`. It sounds like you need to use a debugger to figure out where the program is getting stuck. Point of order too - if you have a specific problem, please include it in your question, the GUI freezing is a very different question than patterns of notifications. – hugh Oct 17 '15 at 10:11
  • I have fixed the GUI problem but I am still having a threading issue. Please see my edit – b_pcakes Oct 17 '15 at 20:50
  • Looks like John has given you a pretty comprehensive answer, I'll leave you with that one! – hugh Oct 19 '15 at 18:57