Java Threads
Excerpt from
Chapter 1: Introduction
Introduction to Threading
This is a book about using threads in the Java programming
language and the Java virtual machine. The topic of threads is very
important in Java, so important that many features of a threaded
system are built into the Java language itself, while other features of
a threaded system are required by the Java virtual machine.
Threading is an integral part of using Java.
The concept of threads is not a new one: for some time, many
operating systems have had libraries that provide the C programmer
a mechanism to create threads. Other languages-like Ada-have
had support for threads embedded into the language much as the
support for threads is built into the Java language itself.
Nonetheless, the topic of threads is usually considered a peripheral
programming topic, one that's only needed in special programming
cases.
With Java, things are different: it is impossible to write all but the
simplest Java programs without introducing the topic of threads.
And the popularity of Java ensures that many developers who might
never have considered learning about threading possibilities in a
language like C or C++ need to become fluent in threaded
programming.
Java Terms
We'll start by defining some terms used throughout this book. Since
Java is a new phenomenon, many terms surrounding it are used
inconsistently in various sources; we'll endeavor to be consistent in
our usage of these terms throughout the book.
- Java
-
First is the term Java itself. As we know, Java started out as a
programming language, and many people today think of Java as
being simply a programming language. But Java is much more
than just a programming language: it's also an API specification
and a virtual machine specification. So when we say Java, we
mean the entire Java specification: a programming language, an
API, and a virtual machine specification that, taken together,
define an entire programming and run-time environment. Often
when we say Java, it's clear from context that we're talking
about specifically the programming language, or parts of the
Java API, or the virtual machine. The point to remember is that
the threading features we discuss in this book derive their
properties from all the components of the Java environment
taken as a whole. So while it's possible to take the Java
programming language, directly compile it into assembly code,
and run it outside of the virtual machine, such an executable
may not necessarily behave the same as the programs we
describe in this book.
- Virtual machine, interpreters, and browsers
-
The Java virtual machine is another term for the Java interpreter,
which is the code that ultimately runs Java programs by
interpreting the intermediate byte-code format of the Java
programming language. The Java interpreter actually comes in
two popular forms: the interpreter itself (called java) that runs
programs via the command line or a file manager, and the
interpreter that is built into many popular Web browsers such as
Netscape, HotJava, and the appletviewer that comes with the
Java Developer's Kit. Both of these forms are simply
implementations of the Java virtual machine, and we'll refer to
the Java virtual machine when our discussion applies to both.
When we use the term java interpreter, we're talking specifically
about the command line, standalone version of the virtual
machine; when we use the term Java-enabled browser (or, more
simply, browser), we're talking specifically about the virtual
machine built into these Web browsers.
- Programs, applications, and applets
-
This leads us to the terms that we'll use for things written in the
Java language. Generically, we'll call such entities programs. But
there are two types of programs a typical Java programmer
might write: programs that can be run directly by the Java
interpreter and programs designed to be run by a Java-enabled
browser. Much of the time, the distinction between these two
types of Java programs is not important, and in those cases, we'll
refer to them as programs. But in those cases where the
distinction is important, we'll use the term applets for programs
running in the Java-enabled browser and the term applications
for standalone Java programs.
- Thread Overview
-
This leaves us only one more term to define: what exactly is a
thread? The term thread is shorthand for thread of control, and a
thread of control is, at its simplest, a section of code executed
independently of other threads of control within a single program.
Thread of Control
Thread of control sounds like a complicated
technical term, but it's really a simple concept: it is the path taken
by a program during execution. This determines what code will
be executed: does the code in the if block get executed, or does
the else block? How many times does the while loop execute? If
we were executing tasks from a "to do" list, much as a computer
executes an application, what steps we perform and the order in
which we perform them is our path of execution, the result of our
thread of control.
Having multiple threads of control is like executing
tasks from two lists. We are still doing the tasks on each "to do"
list in the correct order, but when we get bored with the tasks on
one of the lists, we switch lists with the intention of returning at
some future time to the first list at the exact point we left off.
Overview of Multitasking
We're all familiar with the use of multitasking operating systems to
run multiple programs at one time. Each of these programs has at
least one thread within it, so at some level, we're already
comfortable with the notion of a thread in a single process. The
single-threaded process has the following properties which, as it
turns out, are shared by all threads in a program with multiple
threads as well:
- The process begins execution at a well-known point. In
programming languages like C and C++ (not to mention Java
itself), the thread begins execution at the first statement of the
function or method called main().
- Execution of the statements follows in a completely ordered,
predefined sequence for a given set of inputs. An individual
process is single-minded in this regard: it simply executes the
next statement in the program.
- While executing, the process has access to certain data. In Java,
there are three types of data a process can access: local variables
are accessed from the thread's stack, instance variables are
accessed through object references, and static variables are
accessed through class or object references.
Now consider what happens when you sit at your computer and
start two single-threaded programs: a text editor, say, and a file
manager. You now have two processes running on your computer;
each process has a single thread with the properties outlined above.
Each process does not necessarily know about the other process,
although, depending on the operating system running on your
computer, there are several ways in which the processes can send
each other various messages: a common behavior is that you can
drag a file icon from the file manager into the text editor in order to
edit the file. So each process runs independently of the other,
although they can cooperate if they so choose.
From the point of view of the person using the computer, these
processes often appear to execute simultaneously, although there
are a lot of variables that can affect that appearance. These variables
are dependent on the operating system: for example, a given
operating system may not support multitasking at all, so that no two
programs appear to execute simultaneously. Or the user may have
decided that a particular process is more important than other
processes and hence should always run, shutting out the other
processes from running and again affecting the appearance of
simultaneity.
Finally, the data contained within these two processes is, by default,
separated: each has its own stack for local variables, and each has
its own data area for objects and other data elements. Under many
operating systems, the programmer can make arrangements so that
the data objects reside in memory that can be shared between the
processes, allowing both processes to access them.
Overview of Multithreading
All of this leads us to a common analogy: we can think of a thread
just as we think of a process, and we can consider a program with
multiple threads running within a single instance of the Java virtual
machine just as we consider multiple processes within an operating
system.
So it is that within a Java program, multiple threads have these
properties:
- Each thread begins execution at a predefined, well-known
location. For one of the threads in the program, that location is
the main() method; for the rest of the threads, it is a particular
location the programmer decides upon when the code is written.
- Each thread executes code from its starting location in an
ordered, predefined (for a given set of inputs) sequence.
Threads are also single-minded in their purpose, always simply
executing the next statement in the sequence.
- Each thread executes its code independently of the other threads
in the program. If the threads choose to cooperate with each
other, there are a variety of mechanisms we will explore that
allow that cooperation. Exploiting those methods of co-
operation is the reason why programming with threads is such a
useful technique, but that cooperation is completely optional,
much as the user is never required to drag a file from the file
manager into the text editor.
- The threads appear to have a certain degree of simultaneous
execution. As we'll explore in Chapter 6, the degree of
simultaneity is dependent on several factors-programming
decisions about the relative importance of various threads as
well as operating system support for various features. The
potential for simultaneous execution is the key thing you must
keep in mind when threading your code.
- The threads have access to various types of data. At this point,
the analogy breaks down somewhat depending on the type of
data the Java program is attempting to access.
Each thread is separated, so that local variables in the methods
that the thread is executing are separate for different threads.
These local variables are completely private; there is no way for
one thread to access the local variables of another thread. If two
threads happen to execute the same method, each thread gets a
separate copy of the local variables of that method.
Objects and their instance variables can be shared between
threads in a Java program, and sharing these objects is much
easier between threads of a Java program than sharing data
objects between processes in most operating systems. In fact,
the ability to share data objects easily between threads is another
reason why programming with threads is so useful. But Java
threads cannot arbitrarily access each other's data objects: they
need permission to access the objects, and one thread needs to
pass the object reference to the other thread.
Static variables are the big exception to this analogy: they are
automatically shared between all threads in a Java program.
Don't panic over this analogy: the fact that you'll be programming
with threads in Java doesn't mean you'll necessarily be doing the
system-level type of programming you'd need to perform if you
were writing the multitasking operating system responsible for
running multiple programs. The Java Thread API is designed to be
simple and requires little specialized skill for most common tasks.
Java Threads |
O'Reilly Java Center |
Copyright 1997, O'Reilly & Associates
O'Reilly Home |
Customer Service |
About O'Reilly |
Contact Us |
Search the Catalog |