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 parallel resources.
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.

If you enjoy this Java programming article, please share with friends and colleagues. Follow the author on Twitter for the latest news and rants.

Editorial page content written by Neil Coffey. Copyright © Javamex UK 2021. All rights reserved.