Synchronization and Locks are the keys to share a resource among multiple parallel threads. They help in saving trouble of improper state of any resource and creating any confusion among the threads.
You can think about a resource and threads by taking example of a bank account. Let’s say you have some money in your account(1000 bucks) and you are making a payment (100 bucks) and your friend is transferring you some money(20 bucks) which he took from you long back. We have a variable, let’s say myMoney which hold the total money in account. Now let’s say you are making payment and you know you have 1000 bucks so after transaction it should be 900 in account. In between your transaction your friend started another transaction in which the state of myMoney was 1000 and he added 20 so it becomes 1020. But as your transaction finished it updated it as 900 because the state of myMoney as known last to your transaction was 1000. Thus in this whole process you lost 20 bucks just because the variable myMoney was not shared among two different threads one by one, and that why synchronization is required. Synchronization is required so that a resource can be shared properly among all threads, thus a valid state of resource can be maintained.
Now as we have understood the synchronization, I will explain few points about synchronization and locks and that will give you a better understanding.
- To synchronize, threads have to obtain a lock on the object. Each object has one lock with it, which a thread has to obtain, to access the synchronized code.
- The thread hold the lock until it exits the synchronized method, until then no other thread can enter any of the synchronized methods and blocks in that class, using that object.
- The non-synchronized part, the methods and the blocks of a class can be accessed by multiple threads altogether.
- The lock is released when stack unwinds. Thread can acquire multiple locks together.
- The thread which has acquired a lock on an object can call one synchronization method from another method of same class as it already has the lock.
- Improper Thread synchronization can sometimes lead to deadlock.
Lock and threads
The synchronized blocks and synchronized methods are safeguarded by the lock on the object which is obtained by one thread at a time for execution. The synchronization block can be inside any non synchronized method. When a thread invokes method it can execute the code inside method but outside synchronized block without any hassle, but to go inside the synchronized block it has to obtain the lock on the specified object. The object can be the instance specified using this keyword or any third party class’s instance.
But the most important question is – What happens when a thread can’t get the lock?
If a thread cannot get the lock it goes into pool of waiting threads for that particular thread which has object’s lock right now. Any of these waiting threads can get lock without any biasing, randomly.
Static and Non-static Synchronization
One of the most important and tricky concept of thread synchronization is Static and Non-Static code’s synchronization.
We had studies few of the methods which are very important for maintaining the life cycle of the thread. But to understand better, we have to add more knowledge to those concepts.
Earlier we studied java.lang.Thread class’ methods – sleep(), join(), yield(). We already know how they affect the thread’s life cycle. But to add that we must also remember that even though after calling any of these methods thread’s state changes, but still the thread doesn’t gives up the lock it has obtained.
But there are method’s of java.lang.Object class which act totally different and helps in threads’ interaction.
public final void wait() throws InterruptedException
When a lock has been obtained by a thread, and while being in synchronization block(that means thread is still holding lock) we call wait method on the object(on which we have the lock), the thread moves to waiting state and gives up the lock on object immediately. If we call wait method without having lock on the object it give IllegalMonitorStateException. The wait method also takes time in millis to wait for that time period, but still requires lock on the object to carry on. It throws InterruptedException like sleep method.
public final void notify()
When notify method is called it notifies any one of the thread(decided by the JVM) that it has finished execution, but doesn’t gives up lock until comes out of the synchronized code.
public final void notifyAll()
The notifyAll method notifies all waiting threads on a particular object.
That’s all for now. Definitely try this at home and let us know what do you think about synchronization and locks? Is it difficult or easy? Comment below.