There are two ways to implement threading, and both require you to
implement the Runnable
interface.
Runnable
has only one method, whose signature is:
public void run( );
You must provide an implementation of the
run()
method. When this method returns,
the thread is used up and can never be restarted or reused. Note that
there is nothing special in the compiled class file about this
method; it’s an ordinary method and you could call it yourself.
But then what? There wouldn’t be the special magic that
launches it as an independent flow of control, so it wouldn’t
run concurrently with your main program or flow of control. For this,
you need to invoke the magic of thread creation.
One way to do this is simply to subclass from
java.lang.Thread
(which
also implements this interface; you do not need to declare
redundantly that you implement it). This approach is shown in Example 24-1. Class ThreadsDemo
simply
prints a series of Xs and Ys; the order in which they appear is
indeterminate, since there is nothing in either Java or the program
to determine the order of things.
Example 24-1. ThreadsDemo1.java
/** * Threaded demo application, as a Threads subclass. */ public class ThreadsDemo1 extends Thread { String mesg; int count; /** Run does the work: print a message, "count" number of times */ public void run( ) { while (count-- > 0) { println(mesg); try { Thread.sleep(100); // 100 msec } catch (InterruptedException e) { return; } } println(mesg + " all done."); } void println(String s) { System.out.println(s); } /** * Construct a ThreadsDemo1 object. * @param String m Message to display * @param int n How many times to display it */ public ThreadsDemo1(String m, int n) { count = n; mesg = m; setName(m + " runner Thread"); } /** * Main program, test driver for ThreadsDemo1 class. */ public static void main(String[] argv) { // could say: new ThreadsDemo1("Hello from X", 10).run( ); // could say: new ThreadsDemo1("Hello from Y", 15).run( ); // But then it wouldn't be multi-threaded! new ThreadsDemo1("Hello from X", 10).start( ); new ThreadsDemo1("Hello from Y", 15).start( ); } }
What if you can’t subclass Thread
because
you’re already subclassing another class, such as
JApplet
? There are two other ways to do it: have a
class implement the
Runnable
interface, or use an inner class to
provide the Runnable
implementation. Example 24-2 is code that implements
Runnable
.
Example 24-2. ThreadsDemo2.java
public class ThreadsDemo2 implements Runnable { String mesg; Thread t; int count; /** * Construct a ThreadDemo object * * @param String m Message to display * @param int n How many times to display it */ public ThreadsDemo2(String m, int n) { count = n; mesg = m; t = new Thread(this); t.setName(m + " printer thread"); }
The run method itself does not change, so I’ve omitted it from this listing. To complete the discussion, Example 24-3 is a version of this class that uses an inner class to provide the run method.
Example 24-3. ThreadsDemo3.java
public class ThreadsDemo3 { String mesg; Thread t; int count; /** * Main program, test driver for ThreadsDemo3 class. */ public static void main(String argv[]) { new ThreadsDemo3("Hello from X", 10); new ThreadsDemo3("Hello from Y", 15); } /** * Construct a ThreadDemo object * * @param String m Message to display * @param int n How many times to display it */ public ThreadsDemo3(String m, int n) { count = n; mesg = m; t = new Thread(new Runnable( ) { public void run( ) { while (count-- > 0) { System.out.println(mesg); try { Thread.sleep(100); // 100 msec } catch (InterruptedException e) { return; } } System.out.println(mesg + " thread all done."); } }); t.start( ); }
Here, the run method is part of the anonymous inner class declared in
the statement beginning t = new Thread(...)
. This
runs with no interaction with other classes, so it’s a good use
of an inner class.
To summarize, there are three ways of having a
Runnable
:
Extend Thread
as ThreadsDemo1
did. This works best for standalone applications that don’t
need to extend another class.
Implement the Runnable
interface. This works for
applets that extend JApplet
and cannot extend
Thread
, due to single inheritance.
Construct a Thread
passing an inner class that is
a Runnable
. This is best for tiny run methods with
little outside interaction.
There are other
methods that
I should mention briefly, starting with the Thread
constructors: Thread( )
, Thread("Thread Name")
, Thread(Runnable)
, etc. The
no-argument and name-argument constructors are used only when
subclassing. But what’s in a name? Well, by default, a
thread’s name is composed of the class
name and a number such as a sequence number or the object’s
hashcode; on JDK 1.3 it uses sequence numbers, such as
Thread-0
, Thread-1
, and so on.
These are not very interesting when you need to look at them in a
debugger, so assigning names like “Clock Ticker Thread”
or “Background Save Thread” will make your life easier
when (not if) you wind up having to
debug your
threaded application. Because of this, there are also
getName( )
/setName(String)
methods, which return or change the thread’s name,
respectively.
We’ve seen already that the start( )
method begins the process of assigning
CPU time to a thread, resulting in its run( )
method being called. The corresponding stop( )
method is
deprecated; see Section 24.4, where I also discuss
interrupt( )
, which interrupts whatever the thread
is doing. The method boolean
isAlive( )
returns true if the thread has neither
finished nor been terminated by a call to its stop( )
method. Also deprecated are suspend()/resume( )
, which pause and continue a thread;
they are prone to corruption and deadlocking, so they should not be
used. If you’ve created multiple threads, you can
join( )
a thread to wait for it to finish; see
Section 24.5.
The methods int
getPriority( )/void
setPriority(int)
show and set the priority of a
thread; higher-priority threads get first chance at the CPU.
Finally, wait()/notify( )/notifyAll( )
allow you
to implement classical semaphore handling, for such paradigms as
producer/consumer relationships. There are a few other methods:
see the
Javadoc page for the Thread
class.
3.129.218.45