3. Sleeping Barber
“BAU” Process
Barber cuts hair
When finished, he checks the waiting room
If no one is there, he goes to sleep in the chair
Customers arriving while the barber is asleep wake the
barber
What can go wrong?
Barber finishes, walks to waiting room
Customer arrives and goes to wake the barber
They do not see each other, return and wait
indefinitely
3
4. Dining Philosophers
“BAU” Process
Philosophers alternate between thinking and eating
Two forks are required to eat spaghetti
When finished thinking, philosophers seek forks
When finished eating, philosophers put forks down
What can go wrong?
Process of picking up, putting down forks can
result in each philosopher holding one fork -
none can eat
Dining Philosophers Demo
http://www.doc.ic.ac.uk/~jnm/concurrency/classes/Diners/Diners.html
4
5. Computing
Canonical Model
• Processes spawn threads to do work
• Threads maintain local state but can also
access shared state
• Threads can be active, suspended, blocked
waiting for resources or sleeping
• Threads execute concurrently - truly
concurrently in multi-processor
environments, virtually concurrently in single-
processor environments
• Thread scheduling is managed by the parent
process, operating system and / or application
• Sequencing of operations across different
threads is in general unpredictable
Shared State
5
6. Simple Computing Problem
Bad Timing Web App Hit Counter
• Multi-threaded web app wants to maintain a
count of the number of hits it gets
Read counter
• Shared state is used to maintain the count
• Request processing threads update the count
each time they process a request
• Under heavy load, the app seems to “miss”
Read counter some hits. Why?
Assign counter+1
public void increment() {
Assign counter+1
count = count + 1;
}
Badness results from B reading the counter while A is in process of updating it. This is an example of a
race condition.
6
7. Solution
Semaphore Keep B out while A updates
• Could make “count++” operation atomic (i.e. unable to
be interrupted.) The JDK 1.5 AtomicInteger class
does this.
Close the door • More general solution is to synchronize access to the
shared resource
• Using a semaphore, Thread A signals exclusive access
to the critical section of code that does the update
Knock on door
• Simplest semaphore is a mutex (mutual exclusion - just
one allowed in at a time) and simplest implementation
Update, open door
in Java is via the synchronized keyword
Close door, update
public synchronized void increment() {
count = count + 1;
}
Note that the same solution would work for the sleeping barber (close door to waiting room)
7
8. Synchronized Keyword in Java
• Acts as a mutex on blocks of code
• Can protect entire methods, or blocks within methods
• Uses the concept of a monitor on an object to represent the mutex - code entering a
synchronized block acquires an object monitor
• When no object is specified, the monitor on the object executing the code is implied
• Synchronization locks are reentrant - i.e., if a thread owns an object’s monitor and it enters
another method that requires the same monitor, it is allowed in
• When a thread leaves a synchronized block, it releases the associated monitor (even if an
exception occurs)
Parent object’s monitor Fu’s monitor
public synchronized void foo() { public void foo() { public void foo() {
fu.bar(); synchronized (this) { synchronized (fu) {
} fu.bar(); fu.bar();
} }
} }
8
9. Concurrent Object Access
Method
Object
Threads
Object References
When multiple threads share references to the same object, they can concurrently call the same
method on the object, unless synchronization prevents this. A class is thread-safe if concurrently
executing threads can safely hold references to instances of the class.
9
10. Programmer’s Challenge:
Situational Awareness
• The question always needs to be asked, “will multiple threads hold references to instances
of this class at the same time?” Unfortunately, it is sometimes hard to know.
• Most common use cases involving concurrent access are created by application
containers, often in conjunction with application frameworks. Containers manage
threads and frameworks instantiate objects. Fun begins when the Singleton Pattern is
used by the framework.
Primitive Survival Technique: Avoid the bad neighborhood altogether
• Keep is Stateless Stupid (KISS) - avoid maintaining state across method calls
• Prefer immutable objects - only final fields, all set by constructors
• Never spawn threads - let the container manage them
• Use tested, thread-safe resource providers (e.g. databases) to maintain state (when you are
dragged kicking and screaming into acknowledging the need to maintain state at all)
• Encapsulate parameters needed by methods in value objects and pass these to/from methods
instead of relying on instance fields
10
11. Anatomical Example
public class Foo {
public static final int HOSIERY_THRESHOLD = 1000; No worries
private boolean fubar;
...
public void hose(int ways) {
Careful!
int newWays = generateNewWays();
if (ways + newWays > HOSIERY_THRESHOLD) {
fubar = true;
}
}
• Static final fields are initialized when the class is loaded and don’t change thereafter, so all
threads see the same values - threadsafe
• Method parameters are provided to each thread on the call stack and are only visible to
that thread for the duration of the method - threadsafe
• Local variables declared within methods are only visible to the thread activating the
method for the duration of the method - threadsafe
• Class member fields are visible to all threads, so if two threads can be inside a method
that uses a member field at the same time, care must be taken to synchronize access
11
12. Example - Struts 1.x Actions
Servlet Container 1. When the web app starts, it loads
ActionServlet the Struts ActionServlet (one
ActionServlet instance per web
FooAction
application - a singleton)
BarAction
2. When the ActionServlet is
initialized, it reads its
configuration and loads one
instance each of the Action
classes defined in its configuration
FubarAction (more singletons)
3. When browser requests arrive,
the container assigns processing
threads to requests and passes
requests mapped to the Struts
application to the Struts
ActionServlet instance
4. The Struts ActionServlet calls perform(ActionMapping mapping, ActionForm form, HttpServletRequest
request, HttpServletResponse response) on the single Action instance that it uses for all requests
Consequence: Struts Action classes must be threadsafe!
rtfm://struts.apache.org/1.0.2/userGuide/building_controller.html#action_classes
12
13. Struts 1.x Example (Cont.)
Inside a Struts Action Class:
private String successPath = null;
private String failedPath = null;
private String maxAttemptsPath = null;
public ActionForward perform( ActionMapping mapping, ActionForm
form, HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
// Set forward paths, using request information
setForwardPaths(mapping, request );
...
Depending on processing outcome, forward to configured path
}
private void setForwardPaths(ActionMapping mapping, HttpServletRequest request) {
...
successPath = ...
failedPath = ...
maxAttemptsPath = ...
}
Problem: If two requests for this action are processed concurrently, and the
computed forward paths are different, control can be misdirected.
13
14. Struts 1.x Example - Fix
private String successPath = null;
private String failedPath = null;
private String maxAttemptsPath = null;
public ActionForward perform( ActionMapping mapping, ActionForm
form, HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
// Set forward paths, using request information
ForwardPaths forwardPaths = getForwardPaths(mapping,request);
String successPath = forwardPaths.getSuccessPath();
String failedPath = forwardPaths.getFailedPath();
String maxAttemptsPath = forwardPaths.getMaxAttemptsPath();
...
Depending on processing outcome, forward to configured path
}
private ForwardPaths setForwardPaths(ActionMapping mapping, HttpServletRequest request) {
// Compute and store local variables success, failed, maxAttempt representing paths
...
return new ForwardPaths(success, failed, maxAttempts);
}
Eliminating the member fields makes the class threadsafe. Introduction of a value object
(ForwardPaths inner class not shown) enables data to be safely transmitted to/from the private
helper method.
14
15. Deadlock
Thread 1 Thread 2
Acquire lock A
Acquire lock B
Block waiting to
acquire lock B
Block waiting to
acquire lock A
Thread 1 can’t proceed until it gets the lock that Thread 2 is holding on B. Thread 2 can’t
proceed until it gets the lock that Thread 1 is holding on A. No other threads can do anything
that requires either lock. This kind of situation can cause application servers to “hang.”
15
16. DeadLock Example
Apache Commons Pool provides Maintenance Thread Client Thread
a generic object pooling API and
implementations
Apache Commons DBCP is a Acquire pool lock
database connection pool that Acquire factory
uses Commons Pool as its lock
underlying object pool
Block waiting to
When used together, versions acquire factory
1.2-1.4 of Commons Pool and lock
1.1-1.2.x of Commons DBCP
could create a deadlock (tracked Block waiting to
as DBCP-44 in ASF JIRA) acquire pool lock
Source of the deadlock:
Contention between client
threads borrowing / returning Resolution: Modify pool code to move all
objects and a maintenance thread invocations of factory methods outside of
for locks on the pool and objects synchronized scope (so lock in 0 is released before
used by the pool’s object factory step 2 is attempted)
16
17. Avoiding Deadlocks
Rule number 0: Leave concurrency management to external resource providers or fully
tested frameworks - try to design around the need for synchronization
Rule number 1: When holding a lock, never call any methods that require other locks
Would completely eliminate possibility of deadlock; but unfortunately not always possible
Rule number 2: When you must use multiple locks to perform actions in your application,
establish a hierarchy of locks and always acquire locks in the order determined by the
hierarchy
Rule number 3: Maintain a complete and consistent execution model of application
subsystems and make explicit (via both documentation and test cases) invariants that enforce
lock hierarchy and/or prevent contention for locks
Rule number 4: Pay special attention to exception processing, especially when using explicit
locks (i.e., objects that implement the Lock interface) - make sure locks are released on all
execution paths
17
18. Resources
Java Threads, Scott Oaks, Henry Wong (http://oreilly.com/catalog/9780596007829/index.html?
CMP=ILL-4GV796923290)
The Little Book of Semaphores, Allen B Downey (http://greenteapress.com/semaphores/)
“Concurrent Programming with J2SE 1.5” (http://java.sun.com/developer/technicalArticles/
J2SE/concurrency/) Also read carefully the class javadoc for all of the classes in the
concurrency package
“Hierarchical Ordering of Sequential Processes”, Edsker Dijkstra, working paper (http://
userweb.cs.utexas.edu/users/EWD/ewd03xx/EWD310.PDF)
“Sequential Programming vs Concurrent Programming”, Jerry Cain (http://academicearth.org/
lectures/sequential-programming-concurrent-programming)
A little “OT”:
“On the Nature of Time - Why does Nature Abhor Deadlocks?”, Christine Cordula Dantas
(http://www.fqxi.org/data/essay-contest-files/Dantas_Nattime2_1.pdf?
phpMyAdmin=0c371ccdae9b5ff3071bae814fb4f9e9)
18