Distributed computation is about time and state. That is, in order for more than one component to communicate, state must be shared, and all that takes time.
Most programmers anthropomorphize their work. They think about one thread of control carrying out the entire program in the same way they would if they had to do the job themselves. Modern computers, however, switch between tasks very quickly, and in multi-core, multi-CPU, or distributed systems, two events may take place at exactly the same time. Defects rush to fill the gap between the programmer's model of how a program executes and what happens in reality. These defects are related to unexpected interactions between threads, processes, time, and information. These interactions happen through shared state: semaphores, variables, the file system, and, basically, anything that can store information.
Code Correctness: Double-Checked Locking
Example 1: At first blush it may seem that the following bit of code achieves thread safety while avoiding unnecessary synchronization.
if (fitz == null) {
synchronized (this) {
if (fitz == null) {
fitz = new Fitzer();
}
}
}
return fitz;
The programmer wants to guarantee that only one
Fitzer()
object is ever allocated, but does not want to pay the cost of synchronization every time this code is called. This idiom is known as double-checked locking.Unfortunately, it does not work, and multiple
Fitzer()
objects can be allocated. See The "Double-Checked Locking is Broken" Declaration for more details [1].