THE Java™ Programming Language, Fourth Edition

(Jeff_L) #1

no chance for any cleanupso daemon threads are limited in what they can do. You use the method
setDaemon(true) to mark a thread as a daemon thread, and you use isDaemon to test that flag. By
default, daemon status is inherited from the thread that creates the new thread and cannot be changed after a
thread is started; an IllegalThreadStateException is thrown if you try.


If your main method spawns a thread, that thread inherits the user-thread status of the original thread. When
main finishes, the application will continue to run until the other thread finishes, too. There is nothing special
about the original threadit just happened to be the first one to get started for a particular run of an application,
and it is treated just like any other user thread. An application will run until all user threads have completed.
For all the runtime system knows, the original thread was designed to spawn another thread and die, letting
the spawned thread do the real work. If you want your application to exit when the original thread dies, you
can mark all the threads you create as daemon threads.


You can force an application to end by invoking either the System or Runtime method exit. This method
terminates the current execution of the Java virtual machine and again is like invoking destroy on each
thread. However, an application can install special threads to be run before the application shuts downthe
methods for doing this are described in "Shutdown" on page 672.


Many classes implicitly create threads within an application. For example, the Abstract Window Toolkit
(AWT), described briefly in Chapter 25, provides an event-based graphical user-interface and creates a special
thread for dealing with all associated events. Similarly, Remote Method Invocation, also mentioned in
Chapter 25, creates threads for responding to remote method invocations. Some of these threads may be
daemons and others may not, so use of these classes can keep your application running longer than you may
intend. In these circumstances the use of the exit method becomes essential if there is no other way to
terminate the threads.


14.10. The Memory Model: Synchronization and volatile


Any mutable (that is, changeable) value shared between different threads should always be accessed under
synchronization to prevent interference from occurring. Synchronization comes at a cost, however, and may
not always be necessary to prevent interference. The language guarantees that reading or writing any
variables, other than those of type long or double, is atomicthe variable will only ever hold a value that
was written by some thread, never a partial value intermixing two different writes. This means, for example,
that an atomic variable that is only written by one thread and read by many threads need not have access to it
synchronized to prevent corruption because there is no possibility of interference. This does not help with
getmodifyset sequences (such as ++), which always require synchronization.


Atomic access does not ensure that a thread will always read the most recently written value of a variable. In
fact, without synchronization, a value written by one thread may never become visible to another thread. A
number of factors affect when a variable written by one thread becomes visible to another thread. Modern
multiprocessing hardware can do very strange things when it comes to the way in which shared memory
values get updated, as can dynamic compilation environments at runtime. Further, in the absence of
synchronization the order in which variables are seen to be updated by different threads can be completely
different. To the programmer these things are not only strange, they often seem completely unreasonable and
invariably not what the programmer wanted. The rules that determine how memory accesses are ordered and
when they are guaranteed to be visible are known as the memory model of the Java programming language.


The actions of a thread are determined by the semantics of the statements in the methods that it executes.
Logically, these statements are executed in the order the statements are writtenan order known as program
order. However, the values of any variables read by the thread are determined by the memory model. The
memory model defines the set of allowed values that can be returned when a variable is read. In this context
variables consist only of fields (both static and non-static) and array elements. From a programmer's

Free download pdf