Threads and Concurrent Programming

Threads may be seen as methods that execute at "the same time" as other methods. Normally, we think sequentially when writing a computer program. From this perspective, only one thing executes at a time. However, with today's multi-core processors, it is possible to literally have several things going on at the very same time while sharing the same memory. There are lots of ways that this is done in the real world, and this chapter goes over them in a way that you can apply to your own projects.

14.5 Using Threads to Improve Interface Responsiveness

Multithreaded Drawing: The Dotty Threa

One way to remedy this problem is to create a second thread (in addition to the GUI itself) to do the drawing. The drawing thread will be responsible just for drawing, while the GUI thread will be responsible for handling user actions in the interface. The trick to making the user interface more responsive will be to interrupt the drawing thread periodically so that the GUI thread has a chance to handle any events that have occurred.

Annotation 2020-03-24 220439As Figure 14.14 illustrates, the easiest way to convert Dotty into a thread is to have it implement the Runnable interface:

Annotation 2020-03-24 220541

This version of Dotty will perform the same task as before except that it will now run as a separate thread of execution. Note that its run() method just calls the draw() method that we defined in the previous version. When the Dotty thread is started by the RandomDotGUI, we will have a multithreaded program. 

However, just because this program has two threads doesn’t necessarily mean that it will be any more responsive to the user. There’s no guarantee that the drawing thread will stop as soon as the Clear button is clicked. On most systems, if both threads have equal priority, the GUI thread won’t run until the drawing thread finishes drawing all N dots.

Annotation 2020-03-24 220821

Therefore, we have to modify our design in order to guarantee that the GUI thread will get a chance to handle the user’s actions. One good way to do this is to have Dotty sleep for a short instance after it draws each dot. When a thread sleeps, any other threads that are waiting their turn the will get a chance to run. If the GUI thread is waiting to handle the user’s click on Clear, it will now be able to call Dotty’s clear() method.

The new version of draw() is shown in Figure 14.15. In this version of draw(), the thread sleeps for 1 millisecond on each iteration of the loop. This will make it possible for the GUI to run on every iteration, so it will handle user actions immediately.

Another necessary change is that once the clear() method is called, the Dotty thread should stop running (drawing). The correct way to stop a thread is to use some variable whose value will cause the run loop (or in this case the drawing loop) to exit, so the new version of Dotty uses the boolean variable isCleared to control when drawing is stopped. Note that the variable is initialized to false and then set to true in the clear() method. The for loop in draw() will exit when isCleared becomes true. This causes the draw() method to return, which causes the run() method to return, which causes the thread to stop in an orderly fashion.

Annotation 2020-03-24 221200

Modifications to RandomDotGUI 

We don’t need to make many changes in RandomDotGUI to get it to work with the new version of Dotty. The primary change comes in the actionPerformed() method. Each time the Draw button was clicked in the original version of this method, we created a dotty instance and then called its draw() method. 

Annotation 2020-03-24 221426Annotation 2020-03-24 221526

Figure 14.15: By implementing the Runnable interface, this version of Dotty can run as a separate thread.

In the revised version we must create a new Thread and pass it an instance of Dotty, which will then run as a separate thread:

Annotation 2020-03-24 221711

Note that in addition to a reference to dotty we also have a reference to a Thread named dottyThread. This additional variable must be declared within the GUI.

Remember that when you call the start() method, it automatically calls the thread’s run() method. When dottyThread starts to run, it will immediately call the draw() method and start drawing dots. After each dot is drawn, dottyThread will sleep for an instant.

Notice how the GUI stops the drawing thread. In the new version, Dotty.clear() will set the isCleared variable, which will cause the drawing loop to terminate. Once again, this is the proper way to stop a thread. Thus, as soon as the user clicks the Clear button, the Dotty thread will stop drawing and report its result.

Annotation 2020-03-24 221911