|
Synchronization is a mechanism to coordinate the access to a common data and critical code among multiple threads. Java uses the locking mechanism to implement this coordination.
Thread keeps the acquired lock even when it is not running.
If a thread acquires a lock on an object and then goes from running to one of the not-ready-to-run states ( sleeping, waiting or blocked), it still keeps the lock with it. For instance, if a thread goes to sleep in a synchronized method, it will keep the object’s lock even while it is sleeping. Hence, no other thread can execute that synchronized method (or any other synchronized method/code of that object) for the entire duration it takes for finishing the execution of that synchronized method. Figure 12.10 shows how Pluto cannot acquire the lock the whole time (including the sleeping time, scheduling time) Mickey is executing the synchronized makePayment() method.

Figure 12.10 The thread Mickey keeps lock even while sleeping in a synchronized code
|
@ |
The lock Java provides for each object is a mutex (mutually exclusive) lock. Only one thread can grab such lock at a time. If two threads try to grab it, only one succeeds. The other thread must wait until the first thread releases it. The terms such as mutex, monitor of an object all imply the lock of an object. The term monitor is a bit confusing as it sometimes used for the wait-and-notify mechanism as well. |
A thread can acquire more than one lock.
Imagine that a synchronized method (say drive()) of one object (myCar) is calling a synchronized method (say openGarageDoor()) of another object (myGarageMotor). When a thread enter a synchronized method drive(), it must have acquired the lock on myCar. When it invokes the synchronized method openGarageDoor(), it must acquire the lock on the object myGarageMotor as well. It must wait if necessary. After it gets the lock, the thread can then execute the synchronized method openGarageDoor(). Note that it has both the locks ( a lock on myCar object and a lock on myGarageDoor object). Thus, remember that a thread can acquire as many locks as necessary.
A thread need not re-acquire object’s lock while calling a synchronized method from another synchronized method of the same object.
When a thread acquires a lock and then attempts to call a synchronized method on that same object, there will not be any problem. Since this thread already has the lock for this object, it is free to call other synchronized methods on the same object as long as it holds the lock.
A thread might have to wait as well as contend for acquiring a lock on an object.
When a thread tries to enter a synchronized method of an object and if the object’s the lock is already taken, the thread has to wait until the lock is free. Such thread leaves the running state and enters a blocked (blocked on object’s lock) state. In fact, there can be several threads, all of which could be blocked on the same object’s lock. The moment the lock is released, all of them will contend for it. One of them will get the lock and rest of them must continue to be blocked. Moreover, the Java threading does not guarantee that the thread that has waited the longest will get the lock first. Thus, a Java thread must sit in the pool of all blocked threads for that particular object until it gets the lock. After acquiring the lock, the thread can becomes ready-to-run again. Figure 12.11 shows the waiting pool of many threads. All are trying to acquire the lock.
![]() |
Figure 12.11 A Java object has a waiting pool of threads contending to get its lock