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
.
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
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:
InterruptedException
at any time, for any reason. You should always check the condition that caused you to wait before you proceed. synchronized
and volatile
appropriately. 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.
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.