A thread is an application task that is executed by a host computer. The
notion of a task should be familiar to you even if the terminology is
not.
Suppose you have a Java program to do some task:
public class DoSomething{
public static void main(String[] args) {
Task 1;
Task 2;
Task 3;
…
Task N;
}
}
When your computer runs this application, it executes a sequence of commands. At an
abstract level, that list of commands looks like this:
• Do Task 1
• Do Task 2
• Continue on until you reach Task N
• Exit the Program
Behind the scenes, what happens is somewhat more complicated since the
instructions that are executed are actually machine-level assembly
instructions; each of our logical steps requires many machine
instructions to execute. But the principle is the same: an application
is executed as a series of instructions. The execution path of these
instructions is a thread.
Consequently, every computer program has at least one thread: the thread
that executes the body of the application. In a Java application, that
thread is called the main thread, and it begins executing statements
with the first statement of the main() method of your class. In other
programming languages, the starting point may be different, and the
terminology may be different, but
the basic idea is the same.
Trivia:
For Java applications, execution begins with the main() method of the class being run. What about other Java programs?
In applets, servlets, and other
J2EE programs, execution still begins with the main() method of the
program, but in this case, the main() method belongs to the Java plug-in
or J2EE container. Those containers then call your code through
predetermined, well-known locations. An applet is called via its init()
and start() methods; a servlet is called through its doGet() and
doPost() methods, and so on.
In any case, the procedure is the same: execution of your code begins
with the first statements and proceeds by a single thread sequentially.
In a Java program, it so happens that every program has more than one
thread. Many of these are threads that developers are unaware of, such
as threads that perform garbage collection and compile Java bytecodes
into machine-level instructions. In a graphical application, other
threads handle input from the mouse and keyboard and play audio. Your
Java application is highly threaded, whether you program & code
additional threads into it or not.
Returning to our example, let's suppose that we wrote a program that
performed two tasks: one calculated the factorial of a number and one
calculated
the square root of
that number. These are two separate tasks, and so you could choose to
write them as two separate threads. Now how would your application run?
The answer to that depends on the conditions under which the application
is run. The Java virtual machine now has two distinct lists of
instructions to execute. One list calculates the factorial of a number,
and the other list calculates the square root of the number. The Java virtual machine executes both of these lists almost simultaneously.
Although you may not have thought about it in these terms, this
situation should also be familiar to you from the computer on which you
normally do your work. The program you use to read your email is a list
of instructions that the computer executes. So too is the program that
you use
to listen to music. You're able to read email and
listen to music at the same time because the computer executes both lists of instructions at about the same time.
In fact, what happens is that the computer executes a
handful of instructions from the email application and then executes a handful of
instructions from the music program. It continues this procedure,
switching back and forth between lists of instructions, and it does that
quickly enough so that both programs appear to be executing at the same
time. Quickly enough, in fact, that there are no gaps
in the music.
If you happen to have more than one CPU on your computer, the lists of
instructions can execute at exactly the same time: one list can execute
on each CPU. But multiple CPUs aren't necessary to give the appearance
of simultaneous execution or to exploit the power of threading. A single
CPU can appear to execute both lists of instructions in parallel,
letting you read your email and listen to music simultaneously.
Threads behave exactly the same way. In our case, the Java virtual machine executes a handful of the instructions to
calculate the factorial and then executes a handful of instructions to calculate the square root, and so on.
So threads are simply tasks that you want to execute at roughly the same
time. Why, then, write an application with multiple threads? Why not
just write multiple applications? The answer lies in the fact that
because threads are running in the same application, they share the same
memory space in the computer. This allows them to share information
seamlessly. Your email program and your music application don't
communicate very well. At best, you can copy and paste some data (like
the name of a file) between the two. That allows you to double-click on
an MP3
attachment in your email
and play it in your music application, but the only information that is
shared between the two is the name of the MP3 file.
In a multitasking environment, data in the programs is separated by
default: each has its own stack for local variables, and each has its
own area for objects and other data. All the programs can access various
types of shared memory (including the name of the MP3 file that you
clicked on in your email program). The shared memory is restricted to
information put there by other programs, and the APIs to access it are
usually quite different than the APIs used to access other data in the
program.
This type of data sharing is fine for dissimilar programs, but it is
inadequate for other programs that need to communicate with one another.
Consider a network server that sends stock quotes to multiple clients.
Sending a quote to a client is a discrete task and may be done in a
separate thread. In fact, if the client must acknowledge the quote, then
sending the data in separate threads is highly recommended: you don't
want all clients to wait for a particularly slow client to respond. Here
the data to be sent to the clients is the same; you don't want each
client to require a separate server process which must then replicate
all the data held by every other server process. Instead, you want
multiple threads in one program so that they may share data and each
perform discrete tasks on that data.
Conceptually, the threads seem to be the same as programs. The key
difference here is that the global memory is the entire Java heap:
threads can transparently share access between any object in the heap.
Each thread still has its own space for local variables (variables
specific to the method the thread is executing). But objects are shared
automatically and transparently.
A thread, then, is a discrete task that operates on data shared with other threads.