Jon Simpson
Introduction to Java Threading
In the real world, things happen in parallel. As I type this, people and objects around the world are doing everything imaginable, in parallel to my typing. Computer programs, traditionally, follow as a set of instructions that are run in order, one after another in a simple step by step execution. Parallel languages provide syntactic structure to let us instruct the computer to run blocks of code at the same time as each other, and break out into new processes running concurrently (more on this in a future post). Java allows us to do much the same thing via threads.
Now, why would you need to do this in a Java program? Lets say, for example, you were writing a server program that interacted both to clients on a network, and to the administrator on a command line. Without wishing to get too embedded in the mechanisms of TCP/IP, the basic (and much summarised) process for the network interactions is as follows.
- Receive incoming connection on the specified listen port
- Establish a connection to the client
- Move the connection to a different port on the server, freeing up the listen port, so it can accept new connections
- Monitor the connection, accepting input from the client, processing it appropriately and returning output as necessary
- Drop the connection through failure or explicit termination
You’ll have noticed the emphasised step 4 there. That’s because it’s a task that requires the system to wait endlessly for some input from the user until it can take an action. These are mostly referred to blocking calls, because they block further execution of the code. The code that actually blocks the program will probably look something like this in Java:
while (inputLine = input.readLine()) {
parse the input, do stuff, whatever
}
When the program execution (the step-by-step evaluation) reaches the while statement and sees what it has to read, it will call the readLine() method, which will then freeze the execution until a line comes through the network stack, giving it something useful to return. This actually freezes the entire program, because the current execution step is frozen until we can get a return value from that function.
Obviously, this isn’t particularly good if we’re trying to have many clients and waiting for a line from each one of them, or be responding to other events in a GUI or CLI elsewhere in the program. This is where threads help us out, by letting us run a lot of the same block of code at the same time. For example, we could change the structure of our fictional program as follows.
- Receive incoming connection on the specified listen port
- Establish a connection to the client
- Start a new thread
- Assign this particular connection to the thread, on a different port
- The thread blocks, waiting for some input from the user, and maintains the connection
- The connection is terminated in some way, and the thread stops running
- The main server process, on the listen port is unaffected by what happens in each of the threads, and continues to go about its tasks of making new threads and dealing with incoming connections
So the server is now running a whole bunch of worker threads to do things that would otherwise block the main program execution loop, and keeping everything running at the same time (clever, eh?). A picture’s worth a thousand words, so here’s a diagram showing the runtime structure of our primitive server program. You can see that the worker threads are taking care of each client in parallel, while the main server core runs undisturbed, creating threads at will as it encounters new clients.
Each of these threads is just a Java class noted as extends Thread
, which means it builds upon whatever the Java gods (or API creators, your pick..) give us to work with in the base Thread
class. Luckily for us, they did all the hard work, and all we have to do is implement a method for the signature public void run()
.
When establishing where to use threads and what to use them for, I often find it useful to visualise the program as functional objects, and then work out which of those blocks should be working at the same time. Obviously, if there are no blocking calls within your objects, threading is not a concern for those blocks, but for the ones that do you can effectively use the blocks to construct thread-able items (and, in fact, a solid OO design seems to aid the addition of threading to code no end..)
This is just a basic primer to the concept behind and implementation of threads in Java programs, and I don’t make any claims about being an authority on the subject. Comments/feedback/corrections and criticisms are all welcome.