Threads in Java
a tutorial introduction
(revision 7)
Christian Ratliff cratliff@delorme.com Senior Technology Architect Core Libraries Group, DeLorme 28 August 2002
Demo
SerialPrime.java
Copyright 2002, DeLorme
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.
Copyright 2002, DeLorme
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.
Copyright 2002, DeLorme
Threads and Processes
CPU main run Process 1 Process 2 Process 3 Process 4
GC
Copyright 2002, DeLorme
Oh No! Computer Science!!
Some
critical concepts:
non-determinism race condition concurrency parallel scheduling
At
least I am not charging $10,000 a year!
Copyright 2002, DeLorme
Concurrency vs. Parallelism
CPU CPU1 CPU2
Copyright 2002, DeLorme
Concurrency vs. Parallelism
CPU CPU1 main CPU2 main
RAM
run
main run this.count
run
main main
run
main
Copyright 2002, DeLorme
Whatever! How about some code?
In
Java, thread instances come in two varieties:
java.lang.Runnable java.lang.Thread
Copyright 2002, DeLorme
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()).
Copyright 2002, DeLorme
Demo
counter/CounterThread0.java
Copyright 2002, DeLorme
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()
Copyright 2002, DeLorme
Demo
counter/CounterThread1.java
Copyright 2002, DeLorme
Thread State Diagram
Alive Running new CounterThread1(max); New Thread cntThread.start(); while () { } Runnable Dead Thread run() method returns Blocked
Copyright 2002, DeLorme
Object.wait() Thread.sleep() blocking IO call waiting on a monitor
Demo
counter/CounterThread2.java
Copyright 2002, DeLorme
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:
Copyright 2002, DeLorme
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 Java
can offer many differing semantics:
offers one, coherent mechanism: Who invented the monitor? When?
barriers, reader-writer, critical sections, etc
monitors
Wizards:
Copyright 2002, DeLorme
synchronized
Monitors
basis. Each method on an object which accesses protected resources is marked synchronized.
The
are implemented on a per-object
monitor is a fence around the object. Each synchronized method is a gate in that fence.
Copyright 2002, DeLorme
Inside Monitors
addPrimeToCache PrimeCache
run
primes
maxPrime
main
isPrime
Copyright 2002, DeLorme
Inside Monitors
addPrimeToCache PrimeCache
primes
maxPrime
main
run isPrime
Copyright 2002, DeLorme
Inside Monitors
addPrimeToCache PrimeCache
primes
maxPrime
main
isPrime
Copyright 2002, DeLorme
Inside Monitors
addPrimeToCache PrimeCache
primes
maxPrime
main
isPrime
Copyright 2002, DeLorme
Inside Monitors
addPrimeToCache PrimeCache
primes
maxPrime
isPrime
Copyright 2002, DeLorme
Demo
sieve/SieveThread0.java
Copyright 2002, DeLorme
Other uses of synchronized
There
are 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.
Copyright 2002, DeLorme
*SNORE*
WAKE UP! SNACK TIME!
Copyright 2002, DeLorme
Signalling
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!
Use
Copyright 2002, DeLorme
Signalling
Object.wait() Gives up ownership of the monitor. Blocks until timeout, interruption, or notification. On waking, the thread enters the monitor acquisition phase.
Copyright 2002, DeLorme
Object.notify() Object.notifyAll() Does not give up ownership of the monitor. Wakes an arbitrary, or all, thread(s) blocked on the monitor. No thread preference!
Demo
sieve/SieveThread1.java
Copyright 2002, DeLorme
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.
Copyright 2002, DeLorme
java.lang.ThreadGroup
When
an exception is emitted by the Thread.run method, the method ThreadGroup.uncaughtException is called.
a class from ThreadGroup. Override the uncaughtException method, relaying the thread and exception information.
Derive
Copyright 2002, DeLorme
Demo
group/SieveThread.java
Copyright 2002, DeLorme
Jane, stop this crazy thing!
There
are three ways to halt a thread:
Thread.stop(), Thread.destroy()
The wrong way
Thread.suspend(),
The long way
The
thread tests a control flag in the instance destroy a dependent resource
The pull-the-rug-out way
Thread.interrupt(),
Copyright 2002, DeLorme
Demo
halt/SieveThread.java
Copyright 2002, DeLorme
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).
Copyright 2002, DeLorme
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 nonreordered semantics as well.
Copyright 2002, DeLorme
Three Concurrency Risks
class Test { static int i = 0; static int j = 0; static void one() { i++; j++; } static void two() { System.out.println("i=" + i + " j=" + j); } } } class Test { static int i = 0; static int j = 0; static synchronized void one() { i++; j++; } static synchronized void two() { System.out.println("i=" + i + " j=" + j); }
Copyright 2002, DeLorme
Three Concurrency Risks
class Test { static int i = 0; static int j = 0; static void one() { i++; j++; } static void two() { System.out.println("i=" + i + " j=" + j); } } } class Test { static volatile int i = 0; static volatile int j = 0; static void one() { i++; j++; } static void two() { System.out.println("i=" + i + " j=" + j); }
Copyright 2002, DeLorme
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.
Copyright 2002, DeLorme
Advanced Topics
Thread
scheduling issues: one-to-one, many-to-one, many-to-many. Thread pooling implementations. Deadlock detection and prevention.
Copyright 2002, DeLorme