Java Keywords (Part XXI): synchronized

Java keyword list

abstract continue for new switch
assert default goto* package synchronized
boolean do if private this
break double implements protected throw
byte else import public throws
case enum instanceof return transient
catch extends int short try
char final interface static void
class finally long strictfp volatile
const* float native super while
Keyword marked with an asterisk (*) are keywords that, although valid, are not used by programmers.
Before diving into the use of the synchronized keyword, we must understand concurrency. I will do my best to summarize the concept of concurrency first and then provide use cases for using synchronization.

What is concurrency?

The dictionary definition of the word concurrent is "occurring, arising, or operating at the same time." In computing, this means that a certain operation, or group of operations, must be executed at the same time. In modern computing, this is often taken for granted. I am old enough to remember the old days where you could only execute one program at a time. So, if you wanted to execute a second program, you had to terminate the first before attempting to run the second. Even programs like Microsoft Word had to abide by these rules: If you wanted to open a second document, you had to close the first. Eventually, CPUs went from single core, to dual, to quad, etc., giving us the ability to execute programs "simultaneously." Notice how the word simultaneously was purposely enclosed in quotes. Please do not mistake "concurrency" with "parallelism." Concurrency is the task of running and managing (mainly managing) the multiple computations at the same time. While parallelism is the task of running multiple computations simultaneously. With concurrent processing, the Operating System takes on the task of executing programs simultaneously, but at any given instance of time it's actively working on one specific task.

Take for example the following use case. A person opens Microsoft Word and starts editing 3 documents for a task at work. At any given moment, the person is actively editing one document while the other two are minimized. The person switches between document until all three documents are properly edited. The person edited those documents concurrently, not in parallel. I hope that clarifies the difference between concurrent and parallel processing. Regardless, synchronization is extremely important for both concurrent and parallel processing.

What is synchronization?

Synchronization means the act of being synchronous. That's not very helpful if you don't understand synchronicity. Synchronous means "happening, existing, or arising at precisely the same time." You often see hear in movies "let's synchronize our watches." When they do this, they set the time on their watches to the exact same value, down to the millisecond. Synchronization involves precision. One millisecond off, and you are no longer synchronized. This is the same in computing.

Suppose you write code that reads from and writes to a file. Your application is multi-threaded because different users may decide to read or write to files at different points in time. While you may need to support many simultaneous users, what happens if all your concurrent users need to access the same file at the same time? This is not necessarily a problem if they all need to read the file, but what happens if one decides to write to the file? What happens first? What if two or more decide to write to the file? Will one user overwrite inadvertently what another user wrote? If these actions are not correctly handled, this can be a huge mess. To avoid this mess, as programmers, we need to establish some kind of control for code that can be executed concurrently. The keyword synchronized helps with, but does not fix, concurrency issues.

This article will not get into why or when synchronize is needed. That is a very long and complicated topic. It will simply show you how to use this keyword. To learn more about concurrent programming in Java, please visit The Java™ Tutorials Lesson: Concurrency.

Using the synchronized keyword

The best strategy for using the synchronized keyword is to limit the scope of the synchronized block to the smallest size possible. This means you can synchronize a single line of code inside a function. This is known as a synchronized statement.

public void someMethod() {
    // step 1
    // step 2
    // step 3
    // synchronized statement
    synchronized (...) {
        // step 4
    }
    // step 5
}
or simply synchronize the entire method

public synchronized void someMethod() {
    // code omitted
}

What goes inside the parentheses of the synchronized block?

Remember the example of the synchronized statement?

synchronized (...) {
    // step 4
}
What goes in the place of the ellipsis (...)?

Intrinsic Locks

Unlike synchronized methods, synchronized statements must specify the object that provides the intrinsic lock. Synchronization is built around an internal entity known as the intrinsic lock. Every object has one. What that means for this topic is that you can place any object instance in place of the ellipsis (within reason). Before I continue, I must point out the obvious. Synchronized methods did not have an object serving as the intrinsic lock, or did they? As a matter of fact, they do have an instrinsic lock. In the case of synchronized methods, the object containing the method is the instrinsic lock. In other words, the intrinsic lock is the object itself (this). The only difference is that you do not set it explicitly. It is implicit. In the case of synchronized statements, you could pass this, or you can pass an instance of another object serving as the lock. A word of caution, Java recommends not to use String or any of the other primitive type wrapper classes, like Integer, Long, and others. You can also place (this) as the lock.

synchronized (this) {
    // step 4
}
Let's summarize. The Java programming language provides two basic synchronization idioms: synchronized methods and synchronized statements. The keyword synchronized is used for both. In the case of synchronized methods, the keyword synchronized is placed immediately after the access modifier. In the case of synchronized statements, you must provide an intrinsic lock object; either this or some other instance of an object that will be served as the lock.

To learn more about concurrency in Java, click on the link I previously provided. To learn mora about using synchronized keyword, visit Synchronized Methods and Intrinsic Locks and Synchronization to learn more about synchronized statements.

That is all for this article. I hope it was useful to you. See you next time! Next up, Part XXII: volatile

Comments

Popular posts from this blog

Implementing Interfaces with Java Records

Customizing Java Records

Exception Handling: File CRUD Operations Example