Sign In/My Account | View Cart  

advertisement

AddThis Social Bookmark Button

Listen Print Discuss

Controlling Threads by Example
Pages: 1, 2, 3, 4

The SWING pros will immediately notice that the SwingUtilities.invokeLater solves our problem. The method setTextArea(..) first creates a string from the list of files and then uses invokeLater(..) to set the text area field on the screen. By wrapping the code in SwingUtilities.invokeLater(..), we effectively call the code from the event dispatcher thread. The invokeLater method simply queues the Runnable object in the event dispatcher queue. The SWING event dispatcher thread detects the message and runs the code in the run() method. Figure 4 shows a sequence diagram for what happens when a user clicks on the Search button.

Figure 4.
Figure 4. Sequence of events when the user clicks on the Search button

Now that we have started a thread, how do we stop it? Java provides us with a particularly important feature to interrupt the thread. The syntax is:

thread.interrupt();

The interrupted thread needs to periodically check whether the thread has been interrupted. If so, the thread needs to break out of any for(..) or while(..) loop and exit from the time-consuming task. Note that this code needs to be inserted by the developer and is not automatically available. The JDK does provide a stop() method on the thread class. However, this method has been deprecated and is dangerous to use. In our code, the implementation is simple. The following is done when the user clicks on the Cancel button:

if (sThread != null) {
    sThread.interrupt();
}

Note that the SearchThread class simply delegates all of the responsibility of searching to the FileFinder class. So, somehow the FileFinder class needs to know that an interrupt has been sent to it. Any thread can check whether it has been interrupted by using the following:

Thread.currentThread().isInterrupted()

If it returns true, the thread was interrupted. So, the SearchThread would have to periodically check whether it was interrupted and, if so, exit. Note that there must be a balance between the liveliness of a thread and the performance degradation that may occur due to too many checks for interrupt; too many checks would improve the liveliness of the thread, since it can respond to the interrupt faster. In our implementation, the check is done before every file is searched. Figure 5 shows a sequence diagram for what happens when a user clicks on the Stop button.

Figure 5.
Figure 5. Sequence of events when the user clicks on the Stop button

The implementation still has some glaring issues:

  • The user still must wait until the end to see whether there are any results.
  • There is no indication of the progress of the task. The user only sees "Working ..." but does not know how much is done.

Determining the Thread Progress

In this iteration, we will add the capability to show the search progress. The interface will not look much different (see Figure 6).

Figure 6.
Figure 6. User interface for monitoring task

When the Search button is clicked, the Cancel button will be enabled. Also, the results will be displayed when available (rather than at the end), and the status field will show the percentage completed as above. To implement the above functionalities, we will have to refactor the FileFinder code so that the search thread is aware of the percentage of the task. The current functionality (FileFinder) does not calculate upfront how much of the work needs to be done. So, let us create a new class called TokenSearchWork, which will have two methods:

  • getAllDirectories(): Determines which directories need to be searched. This will tell the search thread the scope of the task to be performed. It effectively divides the task into multiple subtasks.
  • findFilesInDirectory(): Searches for a token in a specified directory.

Pages: 1, 2, 3, 4

Next Pagearrow