COMP 310/510
Fall 2013

Lab10:  ChatApp Design continued & simple Threads

Home  Info  Owlspace (310)   Owlspace (510)   Java Resources  Eclipse Resources  Piazza

In today's lab, we will be working in small groups to design the interfaces and protocols for the ChatApp project.

For reference:

Discussion Topics

Threads, simply

A "thread" is a path of program execution that runs through ones code.   In a typical application, there may be many threads running concurrently (at the same time).    Thus far, we have always written what we think are "single threaded" applications where the entirety of our code is processed by a single path of execution.  However, just run the Java debugger,  pause it anywhere and you will see that in fact, Java is running multiple threads concurrently in your application.    These other "background" threads perform tasks such a "garbage collecting" objects no longer in use and detecting if the application is ending.

Up until now, our applications have all run on Java's GUI event thread, which manages all events that occur in the GUI, e.g. clicking a button.  But RMI is a model process, not a view process, so calls to RMI objects that come from remote machines via stubs (and skeletons), are asynchronous (not locked together in time) and thus not linked to the local machine's GUI.   Thus remote RMI method calls are invoked on a different thread than the GUI event thread.   Java actually creates a new thread (or re-uses an unused thead) for each remote call.  

Modifying GUI elements from RMI method calls can be problematic because the Java standard says that all modifications to any GUI object must take place on the GUI event thread to insure that the modification is done safely and in a well-defined manner.   Attempting to modify a GUI element, say resize it, can result in a "cross-thread invocation error".    For more information on this issue, please see the Resources web page on cross-thread invocations.   Luckiliy, the append() method of a JTextArea is one of the few "thread-safe" GUI methods that will NOT generate a cross-thread invocation error, which definitely makes our lives easier.   Nothing special needs to be done to do a simple text append.

Another issue that comes up is that when we have clicked a button to send a message to another computer, we are processing on the GUI event thread.  This path of execution proceeds to make a remote RMI method calls, e.g. IUser.sendMsg() perhaps via IChatRoom.sendMsg().     But network operations can take a long time with respect to normal internal computer operations, so while the remote machine(s) slowly receive, process and reply, the GUI thread "blocks", that is, it stops dead in its tracks while it waits for the response.   But the result of a blocked GUI event thread is that nothing else involving the GUI can be processed, e.g. other GUI events.    That means that while the GUI thread is blocked, the entire GUI is locked up and inoperable.

That's probably not what you wanted to happen.   The solution is to start up a new thread that will go off on its own to actually send the message and process the returned status object(s).  Luckiliy in Java, creating new threads is very easy.     For more information on threads, please see the Resources web page on Threads.  Also, see the RMI page for tips on threads with RMI.

In the example code below, a utility method is used to send data packets to an  IChatRoom  ( "room") on a new thread.   Notice how an anonymous inner class is used to override the run() method of the Thread class.   The anonymous inner class closes over the data to be sent, giving the new thread access to it.   Another utility method (code not shown) is used to process the IStatus array that the chat room's sendMsg() method returns.    Note that I cannot assume that the IChatRoom object will send the data off on a new thread because a) it could be someone else's IChatRoom implementation over which I have no code control and b) the IChatRoom object fundamentally does not have access to the procesing of the returned IStatus objects, which must also be processed on the sending thread.

	/**
	 * Send a data packet and process the returned data asynchronously on a new
	 * thread
	 * 
	 * @param data
	 */
	public void sendData(final ADataPacket data) {

		// spawn a new thread to handle the actual transmission, thus freeing
		// this thread to return.
		(new Thread() {
			public void run() {
				// Send the data packet to the chat room
				Iterable<ADataPacket> returnStatus = room.relayMsg(data, userStub);
				// process the returned value using a utility method
				processStatusCollection(returnStatus);
			}
		}).start(); // start the new thread
	}

One must be very careful with threads when dealing with RMI.   It is possible to create situations that are very difficult to debug.  Here's a situation that could very possibly come up in the ChatApp but is luckily solved by the above code.

 

Blocking Queues

A cleaner, more scalable technique for implementing the threading needed for situations where data is being passed from one part of a system to another is called the "producer-consumer model" and is easily implemented using a "blocking queue".    For more information please see the following links:

 

 


© 2013 by Stephen Wong