Let's Talk About Synchronized

A look into the Java keyword for protecting methods and blocks from threads.

Let's Talk About Synchronized

Today I'm writing a little article about a special keyword in the Java language (although there are similar concepts and keywords in many other languages). Yup, it's synchronized. I like to ask a question about it to Java candidates, because it tests your knowledge about whether you really understand what it is doing. Let me start with the question, and then we can dive into the technical background afterwards.

My Synchronized Question

Imagine I have a simple class called SortableList (Yes, I'm aware that Java already has list classes like ArrayList that are already easily sortable - imagine I'm working on a breakthrough sort algorithm that is specific to my application so I need my own class). Imagine inside this class there is a method called sort that has been marked as being synchronized:


public class SortableList {
    ...
    public synchronized void sort() {
    	...
    }
    ...
}

The question is simple: Is it possible for two threads to be inside the sort method at the same time?

Do You Understand Synchronization?

Surprisingly, I get a lot of really quick answers to this question, whether it is from seasoned developers or folks that are still relatively new. A lot of them immediately answer with "no, the point of the synchronized keyword is that it only lets one thread go through at a time". To paraphrase, synchronized is about serializing execution through a portion of code, right?.

WRONG.

Threading is a really complicated topic, and a lot of developers actually never really use it directly. Either they are working in web applications where building responses for one client is independent of building responses for other clients, or they simply never encounter a situation requiring synchronization that isn't already handled by some other component. Anyone who has ever used a database like Oracle has taken advantage of the fact that the database has controls in place to make sure data integrity is protected from mutliple users.

The key thing you have to ask yourself is this: when threads are stopped waiting on a synchronized method, what exactly are they waiting for? How do they know it is time to start execution through the method? Here's an analogy: if you have a classroom full of kids, how do you determine whether someone can go to the bathroom? We used to have a block of wood with a key on it. If you were given that block, you could go. Otherwise, you have to wait for the block of wood with the key. This is what we call a semaphore or sometimes more simply a lock.

Things get complicated if you have more than one lock. Imagine you have two locks, and you have to get both to get access to a prize. You grab one, but while you were doing that, someone else grabbed the other one. You don't want to lose the prize, so you keep holding onto your lock. The other person does the same thing. You are now stuck - what we call a deadlock. To resolve this, developers use a convention that you must get the locks in a specific order.

There's a fun analogy of this called the dining philosophers (I picked this cover image for a reason):

Imagine you are at dinner with four other people, and you are all really hungry. In order to eat, however, you must get two forks. If done incorrectly, you can end up with deadlock (you get the fork from the left but are waiting for the right, and if everyone does this, no one gets to eat and are stuck waiting) or livelock (you pick up the left fork, but you can't get the right and put the left back back down - everyone keeps doing this because they can't get both, so even though you aren't stuck, you still can't eat). Suffice to say that syncrhonization can result in some really tricky problems if not thought out correctly.

So back to the original question: in a synchronized method, what are the threads waiting on? What is the lock? If you don't know the answer to that, you don't fully understand synchronization. The answer is the instance object for the method execution. In other words, if I have a SortableList object and a thread begins to execute sort, the thread will use the list object itself as the lock. If it gets the lock, it can proceed, otherwise it must wait. So the answer to the original question is yes - two threads can be inside the sort method if they are using different instances of the class.

Bonus Question

Now imagine I have another method that is marked synchronized:


public class SortableList {
    ...
    public static syncrhonized seedRandomizer() {
        ...
    }
    ...
}

Is it possible for two threads to be in the seedRandomizer method (don't stress too much about what this method does - I just made the name up, and the situation would be the same no matter what the method actually did)? Before you answer, remember the important question: what are the threads waiting for? If you answered no, you would be right in this case. Why? What are the threads using as the lock? The SortableList class object. That's right - for static (i.e., class) methods, the class object itself is used as the lock.

Block Synchronization

There's another type of synchronization that you may be familiar with, and this brings the whole lock idea right to the forefront:


...
synchronized(list) {
    ...
}
...

In this case, it is obvious what the threads are using as the lock. It's a little more subtle in the instance/class method case, but the idea is the same.

Conclusion

I hope if nothing else, this article has helped some folks understand a little better what the keyword synchronized is all about. It isn't serial execution, it's about serial access. If the threads aren't trying to access the same thing, then they can execute in parallel, otherwise, one of the threads will have to wait.

Related Article