What is Lock Interface?
The Lock Interface is similar to an implicit lock acquired by a thread to execute a synchronized method or synchronized block. Lock implementation provides more extensive operations than implicit locks.
The Problems with Traditional synchronized keywords are:
- we are not having any Flexibility to try for a lock without
- There is no way to specify the maximum waiting time for a thread to get a lock so that thread will wait until getting the lock which may create performance problems or cause deadlock.
- If a thread releases a lock then which waiting thread will get that lock we are not having any control over this.
- There is no API to list out all waiting threads for a look.
- The “synchronized” keyword is compulsory we have to use it either at the method level or within the method and it is not possible to use it across multiple methods.
- To overcome All the above problems Sun Introduced “java.util.concurrent.locks” Package in 1.5 version. It also provides several enhancements to the programmer to provide more control over concurrency.
Important methods of Lock Interface.
- void lock(): We can use this method to acquire a lock. If the lock is already available then immediately the current thread will get that Lock else wait until acquiring the lock. The same behavior as the traditional “synchronized” keyword.
- boolean tryLock(): To acquire the lock without waiting. If available then the thread acquires that lock & returns true else returns false and can continue its execution without waiting. In this case, the thread will never enter into a ‘waiting’ state.
- boolean tryLock(long time, TimeUnit unit): If a lock is available then the thread will get a lock and continue its execution. If not available then the thread will wait until a specified amount of time still if the lock is not available thread can continue its execution. As shown in the following case, a thread will wait for one hour to get the lock.
- void lockInterruptibly(): Acquires a lock if it is available and returns immediately. If a lock is not available then it will wait, while waiting if the thread is interrupted then the thread won’t get the lock.
- void unlock(): This method is used to release a lock. To call this method compulsory current thread should be the owner of the lock otherwise we will get R.E-IllegalMonitorStateException.
ReentrantLock
This is an implementation class of the Lock interface.
Reentrant means a thread can acquire the same lock multiple times without any issue.
Internally ReentrantLock increments the thread’s count whenever we call the lock method and decrements the count value whenever the thread calls unlock method, and the lock will be released whenever the count reaches zero.
Constructors:
- ReentrantLock lock = new ReentrantLock();
- ReentrantLock lock = new ReentrantLock(boolean fairness): This will create ReentrantLock with a given fairness policy.
- if true then the longest waiting thread can acquire the lock if it is available. It follows a first come first served policy.
- if false then we can’t expect which waiting thread will get the chance.
- the default value for fairness is false.
Important methods of ReentrantLock:
- void lock()
- boolean tryLock()
- boolean tryLock(long l, TimeUnit t)
- void lockInterruptibly()
- void unlock()
- int getHoldCount(): returns the number of holds on this lock by the current thread.
- boolean isHeldByCurrentThread(): returns if this lock is held by the current thread.
- int getQueueLength(): Returns an estimate of the number of threads waiting to acquire this lock.
- Collection<Thread> getQueuedThreads(): Returns a collection containing threads that may be waiting to acquire this lock
- boolean hasQueuedThreads(): Returns whether any threads are waiting to acquire this lock.
- boolean isLocked(): Checks if this lock is held by any thread.
- boolean isFair(): Returns true if this lock has fairness set true.
- Thread getOwner(): the thread that currently owns this lock
Example:
In the following example instead of using the traditional synchronized method to acquire the lock, we will use ReentrantLock.
class Test {
public static void main(String args[]) throws InterruptedException {
Display d = new Display();
MyThread t1 = new MyThread(“Thread–1”, d);
MyThread t2 = new MyThread(“Thread–2”, d);
t1.start();
t2.start();
}
}
class MyThread extends Thread{
String name;
Display display;
public MyThread(String name, Display display) {
this.name = name;
this.display = display;
}
public void run() {
display.printMessage(name);
}
}
class Display {
ReentrantLock lock = new ReentrantLock();
public void printMessage(String name) {
lock.lock();
System.out.println(“is Locked: ” + lock.isLocked());
System.out.println(“has queued threads ” + lock.hasQueuedThreads());
for (int i = 0; i < 5; i++) {
System.out.println(“Running ” + name);
}
lock.unlock();
}
}
has queued threads true
Running Thread–1
Running Thread–1
Running Thread–1
Running Thread–1
Running Thread–1
is Locked: true
has queued threads false
Running Thread–2
Running Thread–2
Running Thread–2
Running Thread–2
Running Thread–2