Posted by caroljmcdonald
on September 17, 2009 at 1:55 PM PDT
Here is a review of some concurrency tips from Joshua Bloch, Brian Goetz and others.
Here is a review of some concurrency tips from Joshua Bloch, Brian
Goetz and others.
Prefer immutable objects/data
Immutable objects do not change after construction. Immutable objects
are simpler, safer, require no locks, and are thread safe. To
make an object immutable don't provide setters/mutator methods, make
fields private final, and prevent subclassing. If immutability is not an option, limit mutable
state, less mutable state means less coordination. Declare fields
final wherever practical, final fields are simpler than mutable fields.
When threads share mutable data, each thread that reads or writes must
coordinate access to the data. Failing to synchronize shared mutable
data can lead to atomicity failures, race conditions, inconsistent
state, and other forms of non-determinism. These erratic problems are among
the most difficult to debug.
Limit concurrent interactions to well defined points, limit shared
data, consider copying instead of sharing.
Threading risks for Web applications
A Servlet get, post, service method can be called for multiple clients at the same
time. Multi-threaded Servlet Instance and Static variables are shared
and therefore if mutable, access must be coordinated. Servlets are
typically long-lived objects with a high thread load, if you
over-synchronize performance suffers, try to either share immutable
(final) data, or don’t share at all, request arguments and local variables are safer.
Hold Locks for as short a time
Do as little work as possible inside synchronized
regions. Move code that doesn't require the
lock out of synchronized block, especially if
The Lock interface provides more extensive locking operations than
using a synchronized block, one advantage is the ability to not block
if a lock is not available. You should obtain the lock, read or
write shared data only as
necessary, and unlock within a finally clause to ensure that the lock
is released. Below is an example using a ReentrantReadWriteLock:
A way to reduce the time that a lock is held is lock splitting or
lock striping, which uses different locks for state variables instead
of a single lock. This reduces the lock granularity, allowing greater
scalability but you must take locks in a disciplined order or
Prefer executors and tasks to threads
Instead of working directly with threads, use the Java Concurrency
Utilities Executor Framework. The Executor service decouples task
submission from execution policy. Think in terms of runnable tasks and
let an executor service execute them for you.
Executors can be created either directly or by using the factory
methods in the Executors class:
Here is an example that uses the Executor, Executors and
The example is a web service class that handles multiple incoming
connections simultaneously with a fixed pool of threads. A fixed
thread pool is initialized with the newFixedThreadPool method of the
Executors class which returns an ExecutorService object. Incoming
connections are handled by calling execute on the ExecutorService pool
object, passing it a Runnable object. The Runnable object's run method
processes the connection. When the run method completes the thread will
automatically be returned to the thread pool. If a connection comes in
threads are in use, then the main loop will block until a thread is
Prefer Concurrency utilities to wait
Whenever you are about to use wait and notify check and see if there is a class in
java.util.concurrent that does what you need. The concurrent
collections provide high-performance concurrent
implementations of standard collection interfaces such as List, Queue,
BlockingQueues are concurrent queues extended with blocking methods,
which wait (or block) until an element becomes available for retrieving
or space becomes available for storing.
Producer Consumer Pattern
Blocking queues are useful for the Producer Consumer Pattern where
producer threads enqueue work items and consumer threads dequeue and
process work items. Below is an example of a Consumer Pattern for a
logger used by multiple threads. The Logger constructor takes a
BlockingQueue as an input argument. In the run method messages
are retrieved from the
queue and logged. When the queue is empty the logging thread
will block until an message becomes available for retrieving.
is an example of a Producer that uses the logger. A new
instantiated for passing to the logger constructor. In the run
method messages are put into the queue for logging. If the queue
full, the put will block until the logger has removed messages.
Synchronizers are objects that help with coordinating access between threads. The most used
synchronizers are CountDownLatch and Semaphore. The use of synchronizers can eliminate most uses of
wait or notify.
Below is an example
of the use of a semaphore to control access to pool of resources.
Multiple threads can request the use of a resource and return it when
they have finished with it.
In the creator we create a new semaphore with the same size as the pool of resources we're creating.
In the getResource() method the semaphore aquire method is called
to try to aquire a permit to use a resource. If there
are resources available this will return and a resource will be
returned from the pool. If all the resources are in use the call to
aquire will block until another thread calls release on the
semaphore. When a thread finishes with a resource the resource is
returned to the
pool and the release method is called. Both aquire and release can be
considered atomic operations.
Multithreaded Lazy Initialization is tricky
When threads share a lazily initialized field, access to the field must
be synchronized, or non-determinism type bugs can result.
Prefer Normal initialization
use lazy initialization unless an object or field is costly to
initialize and not used often. Normally normal initialization is best
;) Below is a thread safe example of eager initialization for a
singleton, the private final instance field and the private constructor
make it immutable.
If you need to use lazy initialization for performance on a
static field, use the initialize-on-demand holder pattern. This pattern takes advantage of the guarantee that a class will
not be initialized until it is used :
References and More Information:
Java , Second Edition by Joshua Bloch
Concurrency in Practice by Brian Goetz
and Scalable Concurrent Programming: Lessons from the Trenches
Past and Present