16.1 Threads

In the JVM, a thread is represented by an instance of the class Thread. The thread is initialized with an object that implements the interface Runnable. Runnable has the single method run. The run method defines the thread's task. Figures 16.1 and 16.2 show the Runnable and Thread classes.

Figure 16.1 The interface Runnable
 package java.lang; public interface Runnable {    public abstract void run(); } 
Figure 16.2 Part of Thread
 package java.lang; public class Thread implements Runnable {     /** Constructors for Thread.     * Runnable r defaults to this.     * String name defaults to "Thread-n", where n is a counter.     * ThreadGroup group defaults to null. When group is null, the new     * thread is put in the same group as the current thread.     */    public Thread();    public Thread(Runnable r);    public Thread(ThreadGroup group, Runnable r);    public Thread(String name);    public Thread(ThreadGroup, String name);    public Thread(Runnable r, String name);    public Thread(ThreadGroup group, Runnable r, String name);        /** Causes this thread to begin execution.    * The Java virtual machine calls the run method of this thread. */    public synchronized void start();        /** Executes the run method of the Runnable, if there is one.    * Otherwise, do nothing */    public void run();        /** Forces the thread to stop executing */    public synchronized void stop();        /** Set the thread's priority */    public final void setPriority(int);    /** Get the thread's priority */    public final int getPriority();    /** Cause the current thread to yield control */    public static void yield();    /** Cause the current thread to sleep for m milliseconds    * and n nanoseconds */    public static void sleep(long m, int n);    public static void sleep(long m);    /* Other fields and methods omitted. */ } 

When the start method is called on the thread, a new flow of control begins, running concurrently with all other threads. (This is called spawning a new thread.) A new Java stack is created for the new flow of control. The new thread shares the heap and class area with the other threads. The first element on the new stack is a call to the run method of the Runnable object. The new thread proceeds until the run method terminates.

Figure 16.3 depicts a JVM with three threads running. For each thread, the first method on the Java stack is the run method. Each frame in each Java stack still has its own operand stack and its own local variable array.

Figure 16.3. JVM with multiple threads


16.1.1 Example: Multithreaded Web Server

Following is part of an implementation of a simple multithreaded web server. It consists of two classes: WebServer, which runs the server itself, and WebServerConnection, which handles an individual request in a separate thread.

 import java.io.*; import java.net.*; /**  * This represents a connection between a web browser and the  * web server. The run method reads the browser's request, then  * provides the requested page  */ class WebServerConnection implements Runnable {    Socket connection;    public WebServerConnection(Socket connection)    {       this.connection = connection;    }    /**     * This method handles a single request from a web browser.     * Because it is a separate thread, it can execute       simultaneously with other requests     */    public void run()    {       // Read the request from connection.getInputStream()       // Write the results to connection.getOutputStream()       // Close the socket       // Returning terminates this thread    } } /** This class runs the web server. It sets up a ServerSocket  * on port 80 to listen for requests. When a web browser  * connects to that port, a new WebServerConnection is spawned  * in a separate thread so that the server may continue to  * listen for new connections  */ public class WebServer {    public static void main(String args[])    {       try {             // Listen on port 80             ServerSocket sock = new ServerSocket(80);             while(true)             {             // Wait for a connection             Socket connection = sock.accept();             // Spawn a new connection to handle the socket             Runnable connect =                new WebServerConnection(connection);             Thread t = new Thread(connect);             // Set it going             t.start();          }       }       catch(Exception e) {          // Handle errors       }    } } 

The main in WebServer listens for connections from web browsers. When it receives one, it creates a WebServerConnection, which is a Runnable object. It places the connection in a new thread. The call to t.start starts the new thread and returns immediately. This allows the server to go back and listen for new requests while the WebServerConnection handles the request.

Now there are two things happening at once. The original thread running WebServer.main continues by looping back to accept another socket connection. The newly spawned thread executes the method WebServerConnection.run to service the connection. If a new request comes in while the first is being handled, the server spawns yet another thread, and then all three continue simultaneously. The new thread continues until it reaches the end of its run method or when an exception causes it to leave run. When that happens, the new thread is terminated.

Since Thread implements Runnable, it is common to subclass Thread instead of implementing Runnable. An equivalent way to implement WebServerConnection is

 class WebServerConnection extends Thread 

This allows the programmer to condense the Thread creation and Runnable creation into the single call:

 Thread connect = new WebServerConnection(connection); 

which creates the new WebServerConnection, using itself as the Runnable. The new combination Thread and Runnable is then started with


16.1.2 Exceptions and Threads

Although the declaration of run in Runnable specifies that it does not throw any exceptions, it is still possible for run to raise uncaught exceptions. Because run does not declare any exceptions, a Java compiler prohibits any implementation of run from throwing certain kinds of exceptions. This is actually a feature of the Java language, not the JVM itself. The JVM does not require you to declare which exceptions are thrown. If you write in Oolong, your program may throw an exception from run. Even in Java, certain classes of exceptions are permitted, specifically those that are subclasses of Error or RuntimeException.

Since run is at the bottom of the execution stack, there is no method further down the execution stack to handle the exception. The run method terminates, but no exception handler is invoked.

The ThreadGroup containing the thread is notified about the death of the thread by an invocation of the uncaughtException method, which usually prints a stack dump to the console. The stack dump is familiar to most Java programmers, who at one time or another have tried to call a method on null, which causes a NullPointerException that is not handled. The stack dump you see comes from uncaughtException.

Typically, threads use the default thread group. You can create new thread groups that have different error handling for uncaught exceptions. Thread groups fall outside the scope this book. For more information, look at the documentation for java.lang.Thread and java.lang.ThreadGroup.

You might expect that the thread invoking start would get a chance to handle the exception. Recall that the original thread has continued to execute after it invoked start, which returns almost immediately, without waiting for the run method to complete. It is probably doing something totally unrelated by the time the child thread throws the exception and is unprepared to handle an exception.

Programming for the Java Virtual Machine
Programming for the Javaв„ў Virtual Machine
ISBN: 0201309726
EAN: 2147483647
Year: 1998
Pages: 158
Authors: Joshua Engel

Similar book on Amazon

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net