Lock Interface
The Lock interface explained with examples.
We'll cover the following
If you are interviewing, consider buying our number#1 course for Java Multithreading Interviews.
Explanation
The Lock
interface provides a tool for implementing mutual exclusion that is more flexible and capable than synchronized
methods and statements. A single thread is allowed to acquire the lock and gain access to a shared resource, however, some implementing classes such as the ReentrantReadWriteLock
allow multiple threads concurrent access to shared resource. The use of synchronized
methods or statements provides access to the implicit monitor lock associated with every object, but requires all lock acquisitions and releases to proceed in a block-structured way. Locks acquired in a nested fashion must be released in the exact opposite order, and all locks must be released in the same lexical scope in which they were acquired. These requirements restrict how synchronized
methods and statements can be used and Lock
implementations can be used for more complicated use-cases.
The Lock
interface has the following classes implementing it:
ReentrantLock
ReentrantReadWriteLock.ReadLock
ReentrantReadWriteLock.WriteLock
Difference between Lock and Synchronized
If you have worked with synchronized
you may be wondering why we need the Lock
interface and its implementing classes. The answer - locks offer additional functionality and far more flexibility in usage than synchronized methods and statements. For instance:
- A
Lock
can be tested for acquisition in a non-blocking fashion using thetrylock()
method - A
Lock
can be waited upon for acquisition with a specified timeout using thetrylock(timeout)
method. After the timeout the thread abandons its attempt to acquire the lock and moves-on. - A
Lock
can be waited upon for acquisition with the option to interrupt the acquiring thread using thelockInterruptibly
method. - Some
Lock
implementations also provide monitoring and deadlock detection. Additionally,Lock
implementation can provide fair-use mode for locks, guaranteed ordering and non-reentrant use.
The flexibility and functionality of Lock
implementations come at the cost of higher chance of human error since the locks are not automatically released as is the case with synchronized
blocks and statements. The developer must remember to unlock the Lock
in a finally
block and as many times as the lock has been acquired for in case reentrancy is supported. The idiomatic use of any Lock
implmentation follows the below pattern:
Lock ourLock = // ... instantiate a lock
ourLock.lock();
try {
// ... Perform operations
} finally {
ourLock.unlock();
}
Using Lock
and synchronized
Finally, since Lock
implementation is also an object it can be used as the argument to synchronized
statement but such use is discouraged other than for internal implementation of the class. For example, the following is a bad practice:
Lock ourLock = // ... instantiate a lock
synchronized(ourLock){
// ... Not a good idea
}
Create a free account to view this lesson.
Continue your learning journey with a 14-day free trial.
By signing up, you agree to Educative's Terms of Service and Privacy Policy