SCOUG OS/2 For You - April 1999
Cup of Java
Threads and Java
This is the first in a series of articles on various aspects of Java programming. These articles are intended for a programming audience with some basic familiarity with the Java language and JDK.
Introduction
In this article, we'll look at how Java supports multi-threaded applications and, in particular, how to create Java objects that execute in different threads from their parent application. Most of what is described will work on the various platforms that have Java 1.1.x implementations although it should be noted that because not all of these operating systems support threading (e.g., Macintosh), the performance and behavior of the sample programs may not be exactly identical.
Thread Basics
The Java support for threads is encapsulated into two classes within the java.lang package (which are available, without import statements, to all java classes): Thread and ThreadGroup. We'll be looking mostly at Thread. Since it was an assumption up front that Java would contain built-in support for threading, the Thread class makes this support very easy to use.
There are two ways in which processing can be defined to execute in its own thread, both of which are related to the Thread class.
- You can simply define a new class that extends the Thread class and it will automatically be executed in a separate thread.
- You can construct an arbitrary class that implements the Runnable interface and then pass an object of that class in the constructor of a Thread object. This is more flexible (due to Java's limitation to one level of inheritance) and allows you to easily thread any class that you define.
In both cases, you would code a run() method (either in the extension class or the arbitrary class) which would be invoked when the new thread is started. Also, in both cases, you can manage the properties and behavior of the thread by using the associated thread object (in the first case this is the same as the object you create; in the second case it is the thread object you create).
Case 1 - Thread Extension
In this case, you would create a new class definition based on the Thread class:
public class MyThread extends Thread ...
Then you would code a run() method that performs the necessary work that you want the thread to do. Example:
public void run() {
System.out.println("new thread starting...");
... //whatever processing the thread should do
System.out.println("thread ending...");
}
To create and run this object in a separate thread, the parent's start() method would be invoked which performs all of the bookkeeping work associated with thread creation and then executes the thread's run() method. Example:
MyThread newThread = new MyThread();
...
newThread.start();
...
A more complete example is given below. In this example an additional constructor is defined which receives three parameters: a name, an interval, and a count. The run() logic for the thread simply prints out the name, waits for a number of seconds (given by the interval parameter) and repeats this process a number of times (given by the count parameter). A main() method is also included which allows this class to be executed from a command line. The main method starts up three threads with varying intervals and counts.
public class MyThread extends Thread {
private long interval;
private int count;
public MyThread() {
super();
}
public MyThread(String n, long li, int ic) {
super(n);
interval = li*1000; //convert to milliseconds
count = ic;
}
public void run() {
for (int i=0; i
To run this program, you would just type java MyThread at a command line; the output would be "thread1" printed 20 times, "thread2" printed 15 times and "thread3" printed 11 times but the lines of output would be interleaved based on the intervals of 10, 17 and 22 seconds.
Case 2 - Arbitrary Class
For this case, you can basically code an arbitrary class definition which extends (if necessary) any Java class rather than Thread. To allow it to run as a separate thread, however, you must include the Runnable interface implementation in its definition. Example:
MyClass extends java.awt.Frame implements Runnable ...
Because you are implementing this interface, you must also include a run() method in your class definition; this is the only method required by the interface. The processing in this method should include all of the code (and method invocations) that need to be threaded. Example:
public void run() {
... processing
}
To create and execute this class in its own thread, you would then just create an actual Thread object, passing the class object to it, and then execute the Thread object's start() method.
Example:
MyClass aClass = new MyClass();
Thread aThread = new Thread(aClass);
aThread.start();
When aThread.start() is executed, it will, in turn, execute the aClass.run() method as a separate thread.
Life and Death of a Thread
As you can see, creating and starting separate threads in Java is quite easy. However, in real-world applications you often need to interact between the processing threads. Java provides a number of mechanisms for doing this all of which are simply methods on the Thread object. They will work in both of the above cases since, in both cases, an actual Thread object is involved. Let's look at some of these methods.
- To end a thread's execution, just use the stop() method.
- To temporarily pause the execution, use the suspend() method; use the resume() method to start it up again.
- If the thread's run method involves a sleep operation (as in our example above), you can force it out of this mode by invoking its interrupt() method. In this case, the Catch phrase will be entered with an InterruptedException and the method can then do whatever processing is needed for this situation.
- If your application starts a thread and then needs to wait until it is done, it can simply execute the thread's join() method. This can also be done with a timeout interval.
- A yield() method allows the thread itself to let other threads running at the same priority have a chance to execute. The priority can be adjusted using the setPriority(int p) method. It should be noted that this priority is not necessarily related to the host operating system thread or process priorities and should not be used to control the Java process threads relative to OS threads. It is usually only safe to adjust Java thread priorities relative to each other.
But is the thread safe?
Threadsafe coding is always an issue when writing a multi-threaded application. In Java, since objects have their own instance variables, an object is inherently threadsafe with respect to those variables. However, if the code in any of the thread methods accesses and modifies class variables there might be a conflict if multiple instances of the class are executing in different threads. To guard against such a conflict, those methods should use the Java synchronization capability. This is accomplished by adding the "synchronized" attribute to any method which accesses and modifies a class variable. Example:
public class TestClass ... {
static int counter = 0;
...
public synchronized int getCounter() {
counter++;
return counter;
}
...
}
Summary
Java support for multi-threaded applications is designed into the language in an intuitive and easy-to-use manner via the Thread class. Thread methods and properties are defined so that thread creation and manipulation can be accomplished with a minimum amount of programming.
Want more?
A more detailed example of threading can be downloaded from
thread2.zip
It consists of two classes: Thread2Gui and Thread2. Thread2Gui is a frame class which contains three list controls (as you can see in the screen shot below). Each of these is connected to an instance of Thread2. The constructor for this class is given a list control and a time interval (number of seconds). Its "run" method simply displays a message in the list control every nn seconds, where nn is the time interval. The gui class also has buttons for each thread that can suspend, resume or kill it. (Since it was created in the VisualAge visual builder, the source code is a little hard to follow.)
Cup of Java continues next time with Event Handling.
The Southern California OS/2 User Group
P.O. Box 26904
Santa Ana, CA 92799-6904, USA
Copyright 1999 the Southern California OS/2 User Group. ALL RIGHTS
RESERVED.
SCOUG, Warp Expo West, and Warpfest are trademarks of the Southern California OS/2 User Group.
OS/2, Workplace Shell, and IBM are registered trademarks of International
Business Machines Corporation.
All other trademarks remain the property of their respective owners.
|