CSC302 Slides
CSC302 Slides
CSC 302
This lecture slides is based on
Java Concurrency in Practice by
Goetz, et. al.
http://www.javaconcurrencyinpractice.com
Outline
PART 1
Introduction
Basic Thread Safety
Sharing Objects
Composing Objects
Building Blocks
Introduction
Why concurrency?
Need for OS
Resource utilization - why wait? Another program can be running
while another is waiting for resource
Fairness - why wait? Computer resources can be shared via time
slicing
Convenience - why wait? Easier and more desirable to write
several programs that each perform a single task
The needs motivated development of processes
First concurrency: processes
The same motivated development of threads
Threads allow multiple streams of program control flow
within a process
Threads
• Threads execute simultaneously and asynchronously with
respect to one another.
• Benefits of Threads
• Responsiveness (esp. GUIs)
• Exploiting multi-processors
• Simplicity of modeling
• Simplified handling of asynchronous events
Risks of Threads
Java’s “built-in” threads means that concurrency is NOT an
advanced topic
Safety hazards (correctness) (operations in multiple
threads may be interleaved arbitrarily by the runtime)
Liveness hazards (progress) (Indefinite loop where code
that follows the loop never get executed)
Performance hazards (happiness)(Poor service time,
responsiveness, throughput, scalability, resource
consumption)
Threads are Everywhere
PART 1
Introduction
Basic Thread Safety
Sharing Objects
Composing Objects
Building Blocks
Synchronization
Concurrent programming is about writing thread-safe
code and managing access to shared mutable state
Informally, object’s state is its data stored in state variable
Shared implies that a variable could be accessed by
multiple threads
Mutable implies that variable value could change during
its lifetime
Thread safety is about protecting data from uncontrolled
concurrent access
Making an object thread-safe requires using
synchronization to coordinate access to its mutable state
Synchronization…
• Given a mutable variable v
• If multiple threads access v
• AND if one can modify v
• ALL must synchronize access
• This includes read access
• Never attempt to ignore this
• If sync is broken, so is the code (even if it passes tests)
Concurrent Correctness
• Fixing a broken “shared” mutable state var
• Don’t Share var across threads Or
• Make the var immutable! Or
• Synchronize access to var
• Better yet, design thread-safe classes using good object-
oriented techniques
• Encapsulation
• Immutability
• Clear specifications of invariants
What is “Thread-Safe”?
• Definitions are vague and vary
• Problem: what is correctness?
• Thread Safe:
• “Correct” in multi-threaded env
• OR, no more broken in a mult-threaded environment
then in a single-threaded one
• Thread-safe classes encapsulate all synchronization
Example: Unsafe Counter
@NoThreadSafe
public class UnsafeSequence{
private int value;
public int getNext() {
return value++;
}
}
What’s Wrong with That?
• Invariant:
• getNext must return a sequence
• Unlucky execution timing:
PART 1
Introduction
Basic Thread Safety
Sharing Objects
Composing Objects
Building Blocks
Sharing Objects
• Memory Visibility
• Shared object modification should be visible to other threads
• Without synchronization, this may not happen
More about Visibility
“In general, there is no guarantee that the reading thread will
see a value written by another thread on a timely basis, or
even at all” - (JCP p33)
Public class NoVisibility {
private static boolean ready;
private static int number;
PART 1
Introduction
Basic Thread Safety
Sharing Objects
Composing Objects
Building Blocks
Synchronized Collections
• Are thread safe, but
• Composite actions require additional locking for semantic correctness
• Careless use of locking leads to poor performance (think iteration)
Iterators
PART 1
Introduction
Basic Thread Safety
Sharing Objects
Composing Objects
Building Blocks
Advanced Execution
• The Executor Framework
• Decouples task submission and task execution
• Simple interface:
void execute(Runnable command)
• Easiest way to implement a producer-consumer design in an
application
Execution Policies
• Answers
• In what thread will tasks be run
• What order should they be run
• How many concurrently?
• How many queued?
• “Victim” selection
• Setup and Teardown
Policy Examples
• Single-thread (JCP p119)
• 1-thread-per-client (JCP p118)
• Thread Pools: some built in
• newFixedThreadPool
• newCachedThreadPool
• newSingleThreadExecutor
• newScheduleThreadPool
Cancellation & Shutdown
• Reasons for cancellation
• User-requested
• Time-limited
• Events
• Errors
• Shutdown
Cancellation Policy
• “how” “when” and “what” of cancellation
• Not enforced by Java, but generally, use interruption for
cancellation
• E.g. have a cancel() method call the interrupt
Interruption Policy
• Determines how a thread interprets an interruption request
• Tasks are “guests” in a thread
• Preserve interruption status
• Only call interrupt, when you know the interruption policy
Detecting Interrupts
• Polling the thread’s interrupted status
• Detecting an InterruptedException
Non-interruptible Blocks
• Synchronous socket I/O:
• Close the socket
• Asynchronous I/O with Selector:
• Call wakeup
• Lock Acquisition:
• Use the explicit Lock class
• Has a lockInterruptibly() method
Stopping a Thread-Based Service
• ExceutorService extends Executor
• Provides “Lifecycle” options
• shutdown()
• awaitTermination(timeout, unit)
• Any thread based service should provide similar methods
Waiting for Threads
• In the “raw” case, use join()
• A number of Java library classes have advanced “waits” like
ExecutionService’s awaitTermination()
• Obviously, if you implement your own ExecutionService, you’ll
have to use the raw stuff