Christian Ratliff cratliff@delorme.
com
Senior Technology Architect
Threads in Java Core Libraries Group, DeLorme
28 August 2002
a tutorial introduction (revision 7)
Demo
SerialPrime.java
What is a ‘thread’?
Free Online Dictionary of Computing (FOLDOC)
Sharing a single CPU between multiple tasks (or
"threads") in a way designed to minimize the time
required to switch tasks. This is accomplished by
sharing as much as possible of the program
execution environment between the different tasks
so that very little state needs to be saved and
restored when changing tasks.
Wherefore art thou?
► To maintain responsiveness of an
application during a long running task.
► To enable cancellation of separable tasks.
► Some problems are intrinsically parallel.
► To monitor status of some resource (DB).
► Some APIs and systems demand it: Swing.
► To take advantage of multiple processors.
► It looks great on your resume.
Threads and Processes
CPU
main
run
Process 1 Process 2 Process 3 Process 4
GC
Oh No! Computer Science!!
► Some critical concepts:
non-determinism
race condition
concurrency
parallel scheduling
► At least I am not charging $10,000 a year!
Concurrency vs. Parallelism
CPU CPU1 CPU2
Concurrency vs. Parallelism
CPU
CPU1 CPU2
main RAM
main
run
main
run this.count run
main
run
main
main
Whatever! How about some code?
► InJava, thread instances come in two
varieties:
java.lang.Runnable
java.lang.Thread
java.lang.Runnable
► An adapter which enables any given class to
operate as a thread.
► Requires one method be implemented:
public void run()
► Most common method for adding threads to
an application.
► Prevents certain thread operations (e.g.
Thread.isAlive()).
Demo
counter/CounterThread0.java
java.lang.Thread
►A base class with maximum threading
functionality.
► While less common, it is far more powerful.
► Forces the focus of your class to its
“threadedness”.
► Minimum requirements are like Runnable:
public void run()
Demo
counter/CounterThread1.java
Thread State Diagram
Alive
Running
new CounterThread1(max); while (…) { … }
New Thread Runnable Dead Thread
cntThread.start();
run() method returns
Blocked
Object.wait()
Thread.sleep()
blocking IO call
waiting on a monitor
Demo
counter/CounterThread2.java
Cooperative Multithreading
► By adding a Thread.yield() call to the
subthread and the main, all 50 values were
fetched.
► Success depends on careful cooperation
between each thread.
► This is not a safe option.
► Wizards: What is the other problem here?
Accessing Shared Resources
► The only safe mechanism is through locking.
► There are many kinds of locks:
busy-wait-flag, semaphore, mutex, etc
► They can offer many differing semantics:
barriers, reader-writer, critical sections, etc
► Java offers one, coherent mechanism:
monitors
► Wizards: Who invented the monitor? When?
synchronized
► Monitors are implemented on a per-object
basis.
► Each method on an object which accesses
protected resources is marked synchronized.
► The monitor is a “fence” around the object.
► Each synchronized method is a “gate” in
that fence.
Inside Monitors
addPrimeToCache
PrimeCache
run primes maxPrime main
isPrime
Inside Monitors
addPrimeToCache
PrimeCache
primes maxPrime main
run
isPrime
Inside Monitors
addPrimeToCache
PrimeCache
primes maxPrime main
isPrime
Inside Monitors
addPrimeToCache
PrimeCache
primes maxPrime
main
isPrime
Inside Monitors
addPrimeToCache
PrimeCache
primes maxPrime
isPrime
Demo
sieve/SieveThread0.java
Other uses of synchronized
► Thereare two additional situations where
synchronized may be used:
The synchronized statement may be used in a
method to synchronize an arbitrary block of
code.
A static method may be labeled as
synchronized, in which case the monitor it
attached to the enclosing class.
*SNORE*
WAKE UP!
SNACK TIME!
Signalling
► Use of the synchronized attribute alone is
not sufficient.
► If a thread must wait for both access to a
resource and a condition to be satisfied, the
only obvious option is a busy-wait.
► There must be a better way!
Signalling
Object.wait() Object.notify()
► Gives up ownership of Object.notifyAll()
the monitor. ► Does not give up
► Blocks until timeout, ownership of the
interruption, or monitor.
notification. ► Wakes an arbitrary, or
► On waking, the thread all, thread(s) blocked
enters the monitor on the monitor.
acquisition phase. ► No thread preference!
Demo
sieve/SieveThread1.java
Exception Handling
► When an exception is emitted out of the
run() method, the thread is terminated.
► The exception is consumed by the JVM
because once Thread.start() is called, the
created thread is split from the caller.
► Java provides a means for dispatching a
copy of the exception: ThreadGroup.
java.lang.ThreadGroup
► When an exception is emitted by the
Thread.run method, the method
ThreadGroup.uncaughtException is called.
► Derive a class from ThreadGroup.
► Override the uncaughtException method,
relaying the thread and exception
information.
Demo
group/SieveThread.java
Jane, stop this crazy thing!
► There are three ways to halt a thread:
The wrong way
►Thread.suspend(), Thread.stop(), Thread.destroy()
The long way
►The thread tests a control flag in the instance
The pull-the-rug-out way
►Thread.interrupt(), destroy a dependent resource
Demo
halt/SieveThread.java
Three Concurrency Risks
► Atomicity
An atomic operation permits no interruptions.
The JMM promises that 32bit reads and writes
are atomic.
Any types greater than 32bits in size should be
protected with a monitor.
No multi-step operation can ever be atomic
without the use of a monitor.
Fields marked as volatile are always completely
flushed at every write (even 64bit ones).
Three Concurrency Risks
► Ordering
In a synchronized block, instructions are not
reordered (as-if-serial). This is the same as
within try-catch-finally blocks.
When another thread is watching the fields of
the synchronized block, it perceives non-
reordered semantics as well.
Three Concurrency Risks
class Test { class Test {
static int i = 0; static int i = 0;
static int j = 0; static int j = 0;
static void one() static synchronized void one()
{ {
i++; j++; i++; j++;
} }
static void two() static synchronized void two()
{ {
System.out.println("i=" + i + System.out.println("i=" + i +
" j=" + j); " j=" + j);
} }
} }
Three Concurrency Risks
class Test { class Test {
static int i = 0; static volatile int i = 0;
static int j = 0; static volatile int j = 0;
static void one() static void one()
{ {
i++; j++; i++; j++;
} }
static void two() static void two()
{ {
System.out.println("i=" + i + System.out.println("i=" + i +
" j=" + j); " j=" + j);
} }
} }
Three Concurrency Risks
► Visibility
Reads and writes of instance fields must act on
the same data, even on different CPUs.
Exiting a monitor flushs all writes from the
variable cache to main memory.
Acquiring a monitor forces the JVM to reload
any cached variable information.
When a thread exits, its cache is flushed to
memory.
Advanced Topics
► Thread scheduling issues: one-to-one,
many-to-one, many-to-many.
► Thread pooling implementations.
► Deadlock detection and prevention.