Synchronization in Java

Malina Tran
Tech and the City
Published in
3 min readNov 2, 2016

At the surface, concurrency is a fairly straightforward concept: it is a process that describes two or more tasks that are simultaneously executing. In the context of a program, concurrency has its perks: it can improve efficiency and performance, and in dealing with end users, can make for a better user experience (imagine being on a site that only handles one user per time!).

An interesting aspect of Java is synchronization. While I view it as the opposite of concurrency, it is more sensible to understand the concept as a component of concurrency. In a multi-threaded environment, a synchronized object or method does not let two threads access a block of code at the same time. This is enabled by a lock; sections of code are considered to be guarded by a lock which guarantees only one thread executing through them. (Locks are considered expensive because of delays and overhead). Therefore, one thread must complete before a second thread has access. This avoids any potential mix-ups that may occur as a result. For instance, data corruption can happen when multiple threads try to write within the same file or one thread is reading and another is updating.

Also, it is worth noting that constructors cannot be synchronized.

If there are multiple synchronized methods on the same class, and there are dependencies between these methods, bugs can be spawned. Here is an example (based on the docs):

public class SynchronizedClass {
private int counter = 0;
public synchronized void increment() {
counter++;
}

public synchronized void decrement() {
counter--;
}
}

What are the ramifications of creating an instance of SynchronizedClass? For one thing, it is not possible for two invocations of synchronized methods on the same object to interleave. When one thread is executing a synchronized method on an object, all other threads invoking synchronized methods for the same object are blocked, e.g. suspended, until the first thread is done. Secondly, and perhaps more ambiguous to me, is the change in the nature of the relationship between methods. When a synchronized method exits, it establishes a “happens-before” relationship with any other synchronized method that gets invoked. In the event that the object changed within a method, the state of the object is therefore visible to all threads.

The recommendation is to restrict use of a method on a shared object to just one. However , if that’s not possible, solutions include the following (directly quoted from “Clean Code”):

  • Client-Based Locking — Have the client lock the server before calling the first method and make sure the lock’s extent includes code calling the last method.
  • Server-Based Locking — Within the server create a method that locks the server, calls all the methods, and then unlocks. Have the client call the new method.
  • Adapted Server — create an intermediary that performs the locking. This is an example of server-based locking, where the original server cannot be changed.

You can synchronize methods or synchronize blocks. See code snippet below:

1.
public synchronized void method() {
...
...
...
}
2.
public void method() {
synchronized(this) {
....
....
....
}
}

Note that using a synchronized block requires including the reference object this. But, there is an advantage of using the latter: it is a technique that allows much more flexibility in locking specific and small parts of the code. using a synchronized method, however, locks the complete instance of the class. And, as recommended by Brett L. Schuchert in “Clean Code”, synchronized sections should be as small as possible. Synchronized statements should only be comprised of the minimal critical section to avoid decreasing the program’s overall performance.

Pretty nifty! While I haven’t introduced synchronization in my Java code base, it’s still a nifty strategy to dealing with multiple threads and ensuring consistency in data and memory.

--

--