Putting It All Together |
TheRingMaster
class provides two methods that theGamesThread
uses to coordinate its activities with the other threads in the Game application:waitForFirstPlayer
andwaitForGameToEnd
. As the names of these methods imply, these methods causeGamesThread
to wait until for a condition set by another thread.Waiting for the First Player to Register
Therun
method forGamesThread
contains a loop that continues until told to stop by theControlPane
. Each iteration through the loop is a single BINGO game. At the top of the loop, and therefore at the beginning of each BINGO game, therun
method forGamesThread
callsRingMaster
'swaitForFirstPlayer
method which looks like this:In plain English, this method causes thesynchronized void waitForFirstPlayer() { gameNumber++; state = WAITING; socketGate.sendGameStatusMessage(statusString()); while (state == WAITING) { try { wait(); } catch (InterruptedException e) { } } socketGate.sendGameStatusMessage("Beginning count down ... "); }GamesThread
to wait until the first Player registers. Let's look at the code to find out how.First the method sets the
RingMaster
'sstate
toWAITING
. Then,waitForFirstPlayer
enters a loop that causes the current thread towait
as long asstate
is stillWAITING
. Which begs the question "How can this loop ever end?" The answer is that another thread, a thread in the Player application changesstate
and wakes up theGamesThread
. Here's how.To register, a Player application makes a remote method call to
RegistrarImpl
'smayIPlay
method. Part of the registration process involves adding aPlayerRecord
to theRoster
which, if this is the first player to register, also involves calling theRingMaster
'sstartCountDown
method.startCountDown
looks like this:This method changes thesynchronized void startCountDown() { state = COUNTINGDOWN; notifyAll(); }state
toCOUNTINGDOWN
and then callsnotifyAll
.notifyAll
causesGamesThread
to return from itswait
method. Remember that the call towait
is in a loop that continues as long asstate
isWAITING
. So afterGamesThread
returns fromwait
, it checks thestate
, which is no longerWAITING
and so exits the loop. So this method causesGamesThread
to return fromwaitForFirstPlayer
.Thus when
GamesThread
callswaitForFirstPlayer
the effect is that the threads stops and waits until the first player registers for the game. Then the count down begins.[PENDING: consider diagraming the flow of this using diagrams similar to Doug Lea's]
Waiting for the Current Game to End
GamesThread
uses a very similar mechanism to wait until the current game is over. A game ends when a Player wins or theBallAnnouncer
runs out of balls). The code is very similar to that used byGamesThread
to wait for the first player to register so we'll briefly point out the classes and methods involved and let you figure out the rest.After
GamesThread
has created aBallAnnouncer
and started it,GamesThread
callsRingMaster
'swaitForGameToEnd
method which looks like this:Like thesynchronized void waitForGameToEnd() { while (gameInProgress()) { try { wait(); } catch (InterruptedException e) { } } }waitForFirstPlayer
method, this method waits until thestate
changes and indicates that the game is no longer in progress. This causes theGamesThread
to go into a wait state and do nothing.The
state
gets changed whenRingMaster
'ssetGameOver
method gets called.synchronized void setGameOver() { state = GAMEOVER; announceBall(new BingoBall(BingoBall.GAME_OVER)); announcedBalls.removeAllElements(); announcedBalls.push(new BingoBall(BingoBall.FREE_SPACE)); roster.removeAllElements(); notifyAll(); }setGameOver
can be called under two conditions:
- A Player won the game. When a Player wins, it remotely calls
RegistrarImpl
'sBINGO
method which verifies the claim. If the BINGO claim is valid, thenBINGO
callssetGameOver
.- The
BallAnnouncer
announced all of the balls and there was no winning claim from any Player. In this case theBallAnnouncer
callssetGameOver
.setGameOver
changes theRingMaster
'sstate
and then callsnotifyAll
which wakes upGamesThread
.
Putting It All Together |