|
Concurrency : Using Threads
Topics covered include :
What is a Thread? A thread can be loosely defined as a separate, concurrent stream of execution. For example, a web browser, when loading a web page, will usually launch a thread to finish loading each image that is in the page; hence you can see multiple images loading at the same time. Threads are useful for splitting tasks and carrying out work that maybe takes some time in the background, keeping the GUI more responsive. The following code gives an example of a class that extends class Thread :
This class overrides the run() method of class Thread (the default in class Thread does nothing). This method is called when the Thread is started. It loops 10 times printing out the name of the class, finally printing out 'Done' and exiting. While the run() method is executing, the thread is said to be 'active'. The example creates two instances of SimpleThread with different names, starts them both running and waits for a keypress. Because of the randomised delay element in SimpleThread's run() method, it is random which thread will complete first.
Our second example shows :
The Swing GUI compnents were designed to be interacted with from a single thread - the event dispatching thread (which also controls painting of the GUI). The advantages are less overhead in the Swing components by not having to handle multiple thread access safely, and thereby easier for the components to be extended (subclassed), plus events are handled in a predictable order. Therefore, background threads should update Swing components by putting their update / paint requests into the queue of the event-dispatch thread. Swing provides a way to do this conveniently, with two the methods invokeLater() and invokeAnd Wait(). The difference is that invokeAndWait() will wait for the GUI update to complete before continuing. The most generally useful of the two is invokeLater(), which means invoke as soon as possible, but from the event dispatch thread. This is achieved by creating a Runnable object that is placed into the event-dispatch queue.
The example creates a situation where we need to stop a background thread, though this is rarely the case in real-life because threads are either designed to do a finite task or to run indefinitely. The initial Thread API had a stop() method but this is now deprecated as this does not allow the thread to cleanup and release any locks it holds and can cause unstable behaviour. In general, the safe way to stop a thread is simply to make sure that it can reach the end of its run() method. In our example we show a way to achieve this which allows an early exit - by simply having the thread periodically check the state of a flag (the boolean 'stop' in the example). If there is a chance that field 'stop' could be accessed or set from more than one thread either the field should be declared as volatile or it should be made accesible only through a synchronized method. The following code excerpt shows how the new thread is used. The GUI label is passed to each thread so that the thread can update the label's text and then the threads are started.
JLabel label=new JLabel("");
In the action listener fot the stop button, we can safely stop our threads.
The Runnable interface The Runnable interface provides an alternative (and generally better) way to create a new class that can run as a thread. Better, because the class can extend a class other than Thread but still be used as a thread. To implement Runnable means to provide a method with signature public void run().
An instance of the class implementing Runnable can form the content of a Thread. Foo foo=new Foo(); Thread fooThread=new Thread(foo); fooThread.start();
|