4.1 Thread Basics
Example 4-1 is a
simple program that demonstrates how to define, manipulate, and run
threads. The bulk of the program is the main( )
method; it is run by the initial thread created by the Java
interpreter. This main( ) method defines two
additional threads, sets their priorities, and starts them running.
The two threads are defined using two different techniques: the first
is defined by subclassing the Thread class, while
the second implements the Runnable interface and
passes a Runnable object to the Thread(
) constructor. The example also
demonstrates how you might use the important sleep(
), yield( ), and join(
) methods. Finally, Example 4-1
demonstrates the java.lang.ThreadLocal class,
which has been added as of Java 1.2.
Example 4-1. ThreadDemo.java
package je3.thread;
/**
* This class demonstrates the use of threads. The main( ) method is the
* initial method invoked by the interpreter. It defines and starts two
* more threads and the three threads run at the same time. Note that this
* class extends Thread and overrides its run( ) method. That method provides
* the body of one of the threads started by the main( ) method
**/
public class ThreadDemo extends Thread {
/**
* This method overrides the run( ) method of Thread. It provides
* the body for this thread.
**/
public void run( ) { for(int i = 0; i < 5; i++) compute( ); }
/**
* This main method creates and starts two threads in addition to the
* initial thread that the interpreter creates to invoke the main( ) method.
**/
public static void main(String[ ] args) {
// Create the first thread: an instance of this class. Its body is
// the run( ) method above
ThreadDemo thread1 = new ThreadDemo( );
// Create the second thread by passing a Runnable object to the
// Thread( ) construtor. The body of this thread is the run( ) method
// of the anonymous Runnable object below.
Thread thread2 = new Thread(new Runnable( ) {
public void run( ) { for(int i = 0; i < 5; i++) compute( ); }
});
// Set the priorities of these two threads, if any are specified
if (args.length >= 1) thread1.setPriority(Integer.parseInt(args[0]));
if (args.length >= 2) thread2.setPriority(Integer.parseInt(args[1]));
// Start the two threads running
thread1.start( );
thread2.start( );
// This main( ) method is run by the initial thread created by the
// Java interpreter. Now that thread does some stuff, too.
for(int i = 0; i < 5; i++) compute( );
// We could wait for the threads to stop running with these lines
// But they aren't necessary here, so we don't bother.
// try {
// thread1.join( );
// thread2.join( );
// } catch (InterruptedException e) { }
// The Java VM exits only when the main( ) method returns, and when all
// threads stop running (except for daemon threads--see setDaemon( )).
}
// ThreadLocal objects respresent a value accessed with get( ) and set( ).
// But they maintain a different value for each thread. This object keeps
// track of how many times each thread has called compute( ).
static ThreadLocal numcalls = new ThreadLocal( );
/** This is the dummy method our threads all call */
static synchronized void compute( ) {
// Figure out how many times we've been called by the current thread
Integer n = (Integer) numcalls.get( );
if (n == null) n = new Integer(1);
else n = new Integer(n.intValue( ) + 1);
numcalls.set(n);
// Display the name of the thread, and the number of times called
System.out.println(Thread.currentThread( ).getName( ) + ": " + n);
// Do a long computation, simulating a "compute-bound" thread
for(int i = 0, j=0; i < 1000000; i++) j += i;
// Alternatively, we can simulate a thread subject to network or I/O
// delays by causing it to sleep for a random amount of time:
try {
// Stop running for a random number of milliseconds
Thread.sleep((int)(Math.random( )*100+1));
}
catch (InterruptedException e) { }
// Each thread politely offers the other threads a chance to run.
// This is important so that a compute-bound thread does not "starve"
// other threads of equal priority.
Thread.yield( );
}
}
 |