| Home > Core Java FAQ
> Threads FAQ |
| Threads |
| Creating
and Controlling (07) * Thread
Interactions(10) * User
Threads versus System Threads(04) |
| |
|
Q .
What is a thread?
|
Ans :
A thread is
a sequence of executing instructions that can run independently of
other threads yet can directly share data with other threads.
Threads
let you organize your program into logically separate paths of
execution. Multiple threads are like independent agents at your
disposal. You give each one a list of instructions and then send
it off on its way. From the individual thread's perspective, life
is simple: it works on its own list of instructions until it
either finishes the list or is told to stop. In this respect, a
thread resembles a process, or a separately running program.
Data sharing among threads, however,
can make the programmer's life quite complex. All memory for
objects (that is, class instances and arrays) is allocated from
system-managed memory shared by all Java threads. One thread could
change the color of a Button instance, for example,
and that change would be immediately visible to any other thread
holding a reference to the same Button instance. (Not
all data is shared between threads, though—Java threads each
have their own execution stack, which keeps local variables and
method arguments private to a thread.) Data sharing means that
threads can interact with each other in surprising ways, and at
the most unexpected times. Like a house of mirrors, unconstrained
thread interactions can make objects suddenly appear or disappear,
or values mysteriously change. You must work carefully to control
how your threads access shared resources, so that each thread can
read and write data accurately.
Despite the dangers, programming
with threads typically provides significant advantages, including:
- reduced
difficulty in writing highly interactive, multifaceted
programs
- increased
throughput of data
- improved
performance on multiprocessor hardware
The
main power of multithreaded programming lies in letting you tackle
different tasks (very nearly) independently, leaving the worries
of time sharing among tasks to the operating system or virtual
machine. A web browser, for example, can use one thread to format
and display the text of a web page as soon as it arrives, while
other threads manage the slower downloading of large image or
sound files. Without threads, the browser authors would have to
pollute their text display code with periodic checks for new image
data and with calls into the separate body of code to handle image
data. What's more, adding a new operation to be performed while
images are downloading would require yet more code intermingling,
interruption, and greater potential for confusion and bugs.
Second, program throughput usually
improves in multithreaded programs. Blocking one part of the
program, such as the image fetch just mentioned, doesn't prevent
other parts from getting their own work done.
Third, multiprocessor systems are
becoming increasingly common and important. A program written with
multithreading from the ground up can benefit directly and
strongly from running different threads concurrently on different
processors.
Integrated support for threads is a
key facet of Java technology. As explained further on in this
chapter, the Java platform provides synchronization (monitor)
locks, the synchronized keyword, and classes like Thread
and ThreadGroup to make the multithreaded
programmer's life more productive and less error-prone.
|
|
Q . How
do I create a thread and start it running?
|
Ans :
Create an
instance of Thread
or of a Thread subclass, and invoke start
on that instance.
The
Java programming language and virtual machine represent threads
with instances of the Thread class. At the heart of
every thread is a run method, which determines the
body of code the thread will execute in its lifetime. The Thread
class provides two ways to specify what run method the thread will
execute:
- define a run
method in a
Thread subclass
- adopt the run
method of an object that implements the
Runnable
interface
The first approach is
to subclass Thread and override its run
method. This approach is more straightforward, and works best when
the data needed for running the thread is fairly self-contained.
At a minimum, you can define a subclass of Thread
with nothing more than a new run method. The following Thread
subclass, for example, represents a thread of execution that can
print out the square roots of integers from 1 to 1,000,000:
public class SquareRootThread extends Thread {
public void run() {
for (int i = 1; i <= 1000000; ++i) {
System.out.println("Math.sqrt(" + i + ") = "
+ Math.sqrt(i));
}
}
}
This class definition
merely specifies what the thread can do. To execute the thread's
code, you create an instance of the class and invoke start
on it:
Thread t1 = new SquareRootThread();
t1.start();
Invoking start
on a Thread instance starts a new, separately
scheduled thread in the Java Virtual Machine, which then executes
the code specified in the run method of that Thread
subclass.
The second approach, using the Runnable
interface, is less direct but often more useful. A new Thread
instance can be created based on any object from a class that
implements the Runnable interface. A Runnable
object must include a definition for a run method that takes no
parameters and has no return value: public void run() { /*
... */ }.
A Thread instance
created from a Runnable object takes the run method
of that object's class as its own code to execute. For example, Applet
subclasses are commonly defined to implement Runnable
so that their run methods can execute in a separate thread:
public class MyApplet extends java.applet.Applet
implements Runnable {
public void run() {
doThis();
doThat();
}
// ...
}
You can create an
instance of the Thread class using the Thread(Runnable)
constructor. Once you have the Thread instance, you start it just
like any other thread:
// ... "this" refers to the current applet instance
Thread t2 = new Thread(this);
t2.start();
A
primary reason to create a thread from a Runnable
object is to take advantage of full insider access to that object.
Inside an applet, a run method has direct access to
all the applet's data and methods. A Thread subclass,
on the other hand, would be limited to only an outsider's view of
the applet, which is typically just the public methods. In short,
if your thread depends strongly on a certain object for its
execution, you should should define that object's class to
implement the Runnable interface, and construct a Thread
instance from the object.
|
|
Q . How many threads can I create?
|
Ans :
By default, on a Win32 machine, each ("native") thread gets one MB
(1024*1024 bytes) of stack space reserved for it. The memory is not
actually allocated. If it were, you'd run out of memory with dozens of
threads instead of hundreds. The space needs to be reserved as a contiguous block of memory so the stack can grow as needed.
Under Win32, the max amount of memory is 2GB, which corresponds to 2,000 threads each reserving 1MB of memory. That's an upper bound; in
practice you'd run out of other OS resources before running out of
memory. Each thread has some system resources that will be used to
manage the thread -- register storage area, thread-local storage, state
information, exception condition info, etc.
You should design your programs so that you use threads only where necessary. It's almost always a mistake to have one thread per object.
Successful programs are much more likely to have 5 threads (or fewer)
than 500.
|
|
Q . How does Thread's stop method work--can I restart a stopped thread?
|
Ans :
Thread's
stop
method stops a thread permanently—that thread cannot be run
again.
A
Thread instance has three main phases in its
existence:
- prebirth:
creation and configuration, before being started
- life: execution
of code, after being started and before terminating
- death:
postmortem, after terminating, but before being garbage
collected
Creating
and starting a Thread instance brings a thread
to life. A thread continues to execute code until it reaches the
end of its run method or until stop is
invoked on it. The Thread class's stop
method could just as well be named kill or terminate.
The method is not a hint, but a command—it irrevocably ends the
execution phase of the thread. The thread may not die immediately,
because it is in a sleep or a wait, but in that case it is fated
to die as soon as it awakes. Also, any synchronization locks
held by the terminated thread are automatically released. Once the
Thread instance has reached this postmortem phase,
you can no longer run code with it; you can only inspect its
state.
Restarting a stopped thread is not
possible, but you can achieve much the same effect by creating a
new Thread instance to run the same code
|
|
Q . If I create a thread, and then null out the reference to it, what happens to the thread? Does it get interrupted or what?
|
Ans :
The code looks like this:
Thread t = new Thread( my_runnable_obj );
t.start();
...
t = null; // what happens to the thread?
The answer is that you may no longer have a reference to the thread, but the JVM still does. Once a thread is started, and as long as it
keeps running, it is a root object. Root objects are the starting
points for "things in use" that the garbage collector uses.
|
|
Q . How should I stop a thread so that I can start a new thread later in its place?
|
Ans :
Use the
cooperative approach wherever possible: set a flag to indicate
that the thread should stop, but let the targeted thread itself
check for the flag and find a safe place to stop.
Early
Java programs commonly used Thread's stop
method to terminate threads, especially in applet start
and stop methods. For example:
/* common in applets, but NOT recommended: */
Thread myThread;
public void start() {
if (myThread == null) {
myThread = new Thread(this);
}
myThread.start();
}
public void stop() {
myThread.stop();
myThread = null;
}
This
technique is simple but dangerous! Invoking stop
on a thread is analogous to killing a process without warning:
execution ceases, but there are no guarantees about what state the
program is left in. Moreover, if another Thread
instance is created to continue execution where the previous
thread left off, an inconsistent state left by the earlier thread
can inflict serious damage on your program.
In general, you should design your
program so that a running thread can choose a safe place to stop
itself. It's best to save the stop method for cases
when you truly need to terminate an uncooperative thread. (While
on the topic of methods to avoid, note also that suspend
and resume are considered dangerous, or downright
evil, by many Java developers.)
In normal cases, several conditions
are desirable when starting and stopping a thread for an applet:
- Only one thread
at a time can be running the applet code.
- Invoking
start
on the applet either starts a new thread for the applet or
lets an existing thread continue running.
- Invoking
stop
on the applet registers a request that the running thread
stop; a subsequent invocation of start can cancel
that request.
The following code
framework meets the conditions just specified:
boolean stopRequested = false;
Thread myThread;
/** Starts new thread for applet if applet doesn't have one. */
public synchronized void start() {
if (myThread == null) {
myThread = new Thread(this);
myThread.start();
}
stopRequested = false;
}
/** Requests that this applet stop its activity. */
public synchronized void stop() {
stopRequested = true;
}
/** Runs applet code in its own thread. */
public void run() {
// ... thread activity
/* At safe stopping point, check if thread should quit: */
synchronized (this) {
if (stopRequested) {
// ... perform any quick cleanup necessary
stopRequested = false;
myThread = null;
return; // returning from run finishes current thread
}
}
// ... further thread activity and flag checks
}
} // reaching end of run finishes current thread
|
|
Q . How do I specify pause times in my program?
|
Ans :
Use one of
the sleep
methods in the Thread class.
The
Thread class's sleep methods let you
time a thread's activities, or simply wait for a while, without
wasting system resources. In the more commonly used version, you
specify the number of milliseconds (thousandths of a second) that
the current thread should cease execution. For example, to pause
half a second between two portions of code, you could write:
// ... code before the pause
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// ... handle exception
}
// ... code after the pause
Note that sleep
can throw an InterruptedException, which your code
must handle or explicitly ignore.
The sleep methods are
class methods —they belong to the Thread class but
are not invoked on any particular Thread instance.
Nevertheless, a sleep method knows which thread to
pause: the thread that is currently executing.
Note: The wait methods in
class Object provide an important alternative way to
control a thread's pauses
|
|
|
|