Swing and the Event Thread

In a typical Java program with a UI, there are (initially) two threads running, the main thread of the program and, once the UI is made visible, the event thread.  The event thread performs a loop that listens for user events (keyboard and mouse input), processes the event by calling the necessary component methods,  which notify the appropriate listeners in the program by calling actionPerformed, mousePressed, etc., and then waits for the next user event.  The execution of the listener methods also occurs in the event thread.  As we discussed with respect to Vector and ArrayList, there is significant lock management overhead when declaring a method synchronized .  For this reason, none of the Swing component classes' methods are synchronized.  The reason this matters to programmers is that you should never manipulate components in any way from another thread than the event thread.  For example, if you have a thread that attempts to do a setText on a JTextField and simultaneously the user clicks or types in the field or tabs through the field, or the UI attempts to repaint the field, a race condition or a deadlock can occur.

So suppose another thread (say, one that is waiting for a response for a socket read), needs to call a method that ultimately will make some component calls (e.g., to set a field or repaint).  How can you ensure that that method call occurs in the event thread?  The class method EventQueue.invokeLater takes a Runnable and adds an event that runs it as the last item in the event queue.  In practice, this runnable will be the next item executed by the event thread when it finishes processing any current event because the user is not issuing events at microsecond speeds.  For example:
EventQueue.invokeLater(new Runnable() {
   public void run() {
      battleshipUI.enablePlayComponents(false);
      battleshipUI.shootAt(row, column);
   }
});

Waiting for the opponent's move

Another issue for the first programming assignment is that a simple way of coding the program is to make the socket calls in (or from a call in) a component listener.  For example, you might have the UI wait for the opponent's move by issuing a read call to the socket which will block until the opponent writes a move through the socket.  In this case, you are blocking the event thread, which means that the UI cannot respond to the user.  This will function acceptably on the client (except that he/she will not be able to quit), although it's ugly: the button doesn't pop back out and if you put another window over your UI and then move it off, your UI will be blank.  Both effects occur because repaint events are queued but not executed since the thread is blocked.  Furthermore, this won't work for the server, which must be able to play more than one game at a time.  The server must start a separate thread for each client so that it can continue to accept connections, and must display a separate UI for each game.  However, there is one event thread for all Swing components displayed, not one for each frame.  To prevent making a move while the player should be waiting for the opponent to make a move, disable the row and column text fields and the "Place Hit" button.  You must disable the individual components, not the just the panel that contains them (i.e., disable does not propagate to child components).  Also, as you know, the setup components should be disabled while the game is being played.