Recommended: Sing it, brah! 5 fabulous songs for developers
JW's Top 5
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 5 of 5
If your program malfunctions, and you suspect that the problem lies with a thread, you can learn details about that thread
by calling Thread's dumpStack() and toString() methods. The static dumpStack() method, which provides a wrapper around new Exception ("Stack trace").printStackTrace ();, prints a stack trace for the current thread. toString() returns a String object that describes the thread's name, priority, and thread group according to the following format: Thread[thread-name,priority,thread-group]. (You will learn more about priority later in this series.)
Not all threads are created equal. They divide into two categories: user and daemon. A user thread performs important work for the program's user, work that must finish before the application terminates. In contrast, a daemon thread performs housekeeping (such as garbage collection) and other background tasks that probably do not contribute to the application's main work but are necessary for the application to continue its main work. Unlike user threads, daemon threads do not need to finish before the application terminates. When an application's starting thread (which is a user thread) terminates, the JVM checks whether any other user threads are running. If some are, the JVM prevents the application from terminating. Otherwise, the JVM terminates the application regardless of whether daemon threads are running.
In several places, this article refers to the concept of a current thread. If you need access to a Thread object that describes the current thread, call Thread's static currentThread() method. Example: Thread current = Thread.currentThread ();.
When a thread calls a thread object's start() method, the newly started thread is a user thread. That is the default. To establish a thread as a daemon thread, the program
must call Thread's setDaemon(boolean isDaemon) method with a Boolean true argument value prior to the call to start(). Later, you can check if a thread is daemon by calling Thread's isDaemon() method. That method returns a Boolean true value if the thread is daemon.
To let you play with user and daemon threads, I wrote UserDaemonThreadDemo:
// UserDaemonThreadDemo.java
class UserDaemonThreadDemo
{
public static void main (String [] args)
{
if (args.length == 0)
new MyThread ().start ();
else
{
MyThread mt = new MyThread ();
mt.setDaemon (true);
mt.start ();
}
try
{
Thread.sleep (100);
}
catch (InterruptedException e)
{
}
}
}
class MyThread extends Thread
{
public void run ()
{
System.out.println ("Daemon is " + isDaemon ());
while (true);
}
}
After compiling the code, run UserDaemonThreadDemo via the Java 2 SDK's java command. If you run the program with no command-line arguments, as in java UserDaemonThreadDemo, for example, new MyThread ().start (); executes. That code fragment starts a user thread that prints Daemon is false prior to entering an infinite loop. (You must press Ctrl-C or an equivalent keystroke combination to terminate that infinite
loop.) Because the new thread is a user thread, the application keeps running after the starting thread terminates. However,
if you specify at least one command-line argument, as in java UserDaemonThreadDemo x, for example, mt.setDaemon (true); executes, and the new thread will be a daemon. As a result, once the starting thread awakes from its 100-millisecond sleep
and terminates, the new daemon thread will also terminate.
Note that the setDaemon(boolean isDaemon) method throws an IllegalThreadStateException object if a call is made to that method after the thread starts execution.
After studying the previous section's examples, you might think that introducing multithreading into a class always requires
you to extend Thread and have your subclass override Thread's run() method. That is not always an option, however. Java's enforcement of implementation inheritance prohibits a class from extending
two or more superclasses. As a result, if a class extends a non-Thread class, that class cannot also extend Thread. Given that restriction, how is it possible to introduce multithreading into a class that already extends some other class?
Fortunately, Java's designers realized that situations would arise where subclassing Thread wouldn't be possible. That realization led to the java.lang.Runnable interface and Thread constructors with Runnable parameters, such as Thread(Runnable target).
The Runnable interface declares a single method signature: void run();. That signature is identical to Thread's run() method signature and serves as a thread's entry of execution. Because Runnable is an interface, any class can implement that interface by attaching an implements clause to the class header and by providing an appropriate run() method. At execution time, program code can create an object, or runnable, from that class and pass the runnable's reference to an appropriate Thread constructor. The constructor stores that reference within the Thread object and ensures that a new thread calls the runnable's run() method after a call to the Thread object's start() method, which Listing 8 demonstrates:
// RunnableDemo.java
public class RunnableDemo extends java.applet.Applet implements Runnable
{
private Thread t;
public void run ()
{
while (t == Thread.currentThread ())
{
int width = rnd (30);
if (width < 2)
width += 2;
int height = rnd (10);
if (height < 2)
height += 2;
draw (width, height);
}
}
public void start ()
{
if (t == null)
{
t = new Thread (this);
t.start ();
}
}
public void stop ()
{
if (t != null)
t = null;
}
private void draw (int width, int height)
{
for (int c = 0; c < width; c++)
System.out.print ('*');
System.out.print ('\n');
for (int r = 0; r < height - 2; r++)
{
System.out.print ('*');
for (int c = 0; c < width - 2; c++)
System.out.print (' ');
System.out.print ('*');
System.out.print ('\n');
}
for (int c = 0; c < width; c++)
System.out.print ('*');
System.out.print ('\n');
}
private int rnd (int limit)
{
// Return a random number x in the range 0 <= x < limit.
return (int) (Math.random () * limit);
}
}
RunnableDemo describes an applet for repeatedly outputting asterisk-based rectangle outlines on the standard output. To accomplish this
task, Runnable must extend the java.applet.Applet class (java.applet identifies the package in which Applet is located -- I discuss packages in a future article) and implement the Runnable interface.
An applet provides a public void start() method, which is called (typically by a Web browser) when an applet is to start running, and provides a public void stop() method, which is called when an applet is to stop running.
The start() method is the perfect place to create and start a thread, and RunnableDemo accomplishes this task by executing t = new Thread (this); t.start ();. I pass this to Thread's constructor because the applet is a runnable due to RunnableDemo implementing Runnable.
The stop() method is the perfect place to stop a thread, by assigning null to the Thread variable. I cannot use Thread's public void stop() method for this task because this method has been deprecated -- it's unsafe to use.
The run() method contains an infinite loop that runs for as long as Thread.currentThread() returns the same Thread reference as located in Thread variable t. The reference in this variable is nullified when the applet's stop() method is called.
Because RunnableDemo's new output would prove too lengthy to include with this article, I suggest you compile and run that program yourself.
You will need to use the appletviewer tool and an HTML file to run the applet. Listing 9 presents a suitable HTML file -- the width and height are set to 0 because
no graphical output is generated.
<applet code="RunnableDemo" width="0" height="0"></applet>
Specify appletviewer RunnableDemo.html to run this applet.
When you face a situation where a class can either extend Thread or implement Runnable, which approach do you choose? If the class already extends another class, you must implement Runnable. However, if that class extends no other class, think about the class name. That name will suggest that the class's objects
are either active or passive. For example, the name Ticker suggests that its objects are active—they tick. Thus, the Ticker class would extend Thread, and Ticker objects would be specialized Thread objects. In contrast, Rectangle suggests passive objects—Rectangle objects do nothing on their own. Thus, the Rectangle class would implement Runnable, and Rectangle objects would use Thread objects (for testing or other purposes) instead of being specialized Thread objects.
Users expect programs to achieve strong performance. One way to accomplish that task is to use threads. A thread is an independent
path of execution through program code. Threads benefit GUI-based programs because they allow those programs to remain responsive
to users while performing other tasks. In addition, threaded programs typically finish faster than their nonthreaded counterparts.
This is especially true of threads running on a multiprocessor machine, where each thread has its own processor. The Thread and Thread subclass objects describe threads and associate with those entities. For those classes that cannot extend Thread, you must create a runnable to take advantage of multithreading.
Next month, I continue this series by showing you how to synchronize access to shared data.
Read more about Core Java in JavaWorld's Core Java section.