Java Synchronization and concurrency
The words synchronization and concurrency
are overlapping and sometimes synonymous terms. The word synchronization generally means
sharing data between multiple processors or threads, while concurrency refers to
a measure of– or the art of improving– how effectively an application
allows multiple jobs required by that application (e.g. serving
web page requests from a web server) to run simultaneously.
In the past, synchronization and concurrency have been key concerns especially
for server applications– such as web servers– that must deal with a continual
stream of simultaneous requests. But increasingly, they are key issues
for mundane client applications
and more and more programmers will have to
come to terms with them over the coming years.
This is a result of the multicore era that we are now in:
there is a trend for all
computers– including humble desktops and games consoles–to
be multiprocessor machines. Whereas in the past increased computing power
came each year in the form of increased clock speeds (albeit with other
architectural improvements), from now on such increases are likely to come in the form of
increased multiprocessor capability. Programmers who don't get to grips with
multiprocessor programming won't be able to take advantage of the increased
capability of new machines!
Now the good news: Java is generally a good choice of language for multiprocessor
applications, both because of in-built concepts fundamental to the language and because
of a relatively rich concurrency library provided from Java version 5 onwards.
On the following pages, we examine various issues of concurrent programming
in Java. First, a look at some general issues about concurrent programming, and the situation
pre-Java 5 which recent versions of the platform have improved on:
- Java threading tutorial
- If you next to nothing about threads, then this is probably the place to start. If you
essentially know about threads, but want to learn more about the subtleties of making
threaded programs work correctly and efficiently, then the sections below will be of interest.
- Synchronization, concurrency and multitasking:
why is it difficult?
- In this section, we examine some basic issues of concurrent programming such as
sharing resources between CPUs and instruction re-ordering to make best use of available
- Synchronization and concurrency before Java 5
- In this section, we review the "traditional" means of synchronizing data and improving
concurrency in Java 5. In particular, we look at:
- Problems with the Java 1.4 synchronization model
- A discussion of some of the limitations with the previously-mentioned
constructs which Java 5 attempts to resolve.
- Synchronization under the hood
- How synchronization actually works at the processor level, as a precursor to understanding
how Java 5 improves synchronization and concurrency.
Then, we look at various concurrency utilities and language features added in Java 5 which solve some of
the problems discussed in the previous sections:
- final and volatile
- The definitions of these two Java keywords were tightened up in version 5 of the language
so that they now provide important thread-safety features. You should make sure you understand these
two keywords, that are often underestimated and solve threading issues that many programmers overlook.
- The Atomic classes in Java 5
- An overview of classes such as AtomicInteger and AtomicLong, which
effectively expose CAS instructions to the Java programmer.
- Arguably the most important of Java 5's concurrent collection classes. We examine some of
the performance characteristics of ConcurrentHashMap, and example usage.
Other concurrent collection
classes are also examined.
- In particular, Java BlockingQueue implementations
help various scenarios where "workers" or "consumers" pull jobs off a queue that were
created by "producers" (the oft-named producer-consumer pattern.
- Explicit locks
- For cases where synchronized is not adequate, we examine the explicit
lock classes provided in Java 5.
- A CountDownLatch allows you to coordinate the starting and stopping
of multiple threads or tasks.
- Using the Semaphore class, a construct designed to help in the creation
of bounded resource pools such as database connection pools.
- When it is safe to omit synchronization?
- We discuss an example of a rare case when a variable accessed by multiple threads
can be safely accessed without any synchronization at all, when it can be determined that
all possible consequences are still safe.