Java Interface Lock
A synchronisation method called the Lock interface is available as of JDK 1.5. It is comparable to a synchronised block but more complex and versatile. The package java.util.concurrent contains the Lock interface. There are two primary methods: lock() and unlock (). The Lock can be obtained by calling the Lock () method whenever we wish to guarantee that only one thread at a time can access the code. Using the unlock() method, we can release the Lock once the procedure is finished.
Lock vs Synchronized Block
There are a few distinctions between a lock and a synchronised block, as seen below.
Lock | Synchronized block |
There are two methods, Lock () and unlock(), in the Lock interfaces we can employ. | Inside a method, synchronised blocks are present at all times. |
By defining the fairness characteristic, Lock ensures fairness. | Doesn't advocate justice |
Locks have a tryLock() mechanism that determines whether it can obtain the Lock () | If a process cannot acquire a synchronised block, it is stopped. |
To disrupt a waiting process, use the Interrupibilty() function. | A thread in the ready queue cannot be interrupted to reach the synchronised blocks. |
Java Interfaces Mechanisms for Locks
The Lock interface's methods are outlined below.
Method | Description |
Lock void () | the void lock is acquired |
Lock void Interruptible() | obtains the Lock till the interruption of the active process. |
Condition newCondition() | Returning a new condition linked to the active lock instances is a condition(). |
booleantryLock() | obtains the Lock if it is available at the moment given. |
boolean tryLock (long time, TimeUnit unit) | The Lock is only acquired if available during the stated time period and remains unbroken until it is released. |
Void unlock | Returns the Lock with void unlock() |
Implementing Locks
As shown below, JDK provides many Java implementations of the Lock interface.
Reentrant Lock
The Java Lock interface is used by the reentrant properties of the ReentrantLock object. The unlock() method removes the Lock it just acquired that uses the Lock () method. To prevent deadlock, utilising the open () function inside the block header is crucial. Deadlock circumstances Only one process at the moment can execute the synchronised code thanks towards this thread-safe locked.
Code:
ReentrantLock l = newReentrantLock();
intcnt = 0;
voidcounter(){
l.lock();
try{
cnt++;
}
finally{
l.unlock();
}
}
ReentrantReadWriteLock
Some other Java class that supports the Lock protocol is the ReentrantReadWriteLock. It has two locks on it for read-only and write-only access. As soon as nobody is concurrently writing to the variables, this sort of Lock guarantees the security of reading them. As long as there is no writing access to the item, several threads can maintain read-lock access to it. In circumstances where a read process is much more complex than a write operation, this enhances performance.
It is crucial to abide by the following guideline:
- ReadLock: When no thread possesses or demands a reading, many processes may retain access permission.
- WriteLock: When there is neither read/write accessibility to a specific item, only one process is permitted to register permission.
Below is a piece of code that demonstrates the working of ReentrantReadWriteLock.
Code:
ExecutorService exec = Executors.newFixedThreadPool(2);
Map<Integer, String> m = new HashMap<Integer,String>();
ReadWriteLockrwl = newReentrantReadWriteLock();
exec.submit(() ->{
rwl.write-lock().lock();
try{
Thread.sleep(1000);
m.put(1,"Java");
}catch(InterruptedException e){
e.printStackTrace();
}
finally{
rwl.writeLock().unlock();
}
});
Runnable read = () ->{
rwl.readLock().lock();
try{
System.out.println(m.get(1));
Thread.sleep(1000);
}catch(InterruptedException e){
e.printStackTrace();
}
finally{
rwl.readLock().unlock();
}
};
exec.submit(read);
exec.submit(read);
StampedLock
StampedLock is comparable to ReentrantReadWriteLock, with the exception that ReadLocks and WriteLocks both support long-type timestamps. We can provide this timeframe when calling the unlock() technique to remove the Lock. As of Java 8, the StampedLock is accessible. The timestamp can also be used to determine whether a lock is still in effect.
Example of a Java Lock Interface
The Java Lock interface's Lock () and unlock() methods are demonstrated in the straightforward example below, as they operate with many threads. Thus, three lines are created, each of which calls the incCounter() method to increase the counter. Because we used the Lock interface, we can observe that although all three threads have begun, only one is executed at the moment. The Lock ()is called when the current thread acquires the Lock, increments the counter value, and releases it using the unlock() method. This way, it prevents deadlock.
Code:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
publicclassLockDemo{
publicstaticvoidmain(String[]args){
ExecuteTask e = newExecuteTask();
Thread t[] = new Thread[3];
for(inti=0;i<3;i++){
t[i] = newThread(newCounterDemo(e), "Thread " + i);
}
for(inti=0;i<3;i++){
t[i].start();
}
}
}
classCounterDemoimplements Runnable {
ExecuteTask exec;
publicCounterDemo(ExecuteTask exec){
this.exec = exec;
}
publicvoidrun(){
System.out.println("Call executeTask to increment counter: " + Thread.currentThread().getName());
exec.incCounter();
}
}
classExecuteTask{
intcnt = 0;
Lock l = newReentrantLock();
voidencounter(){
l.lock();
try{
cnt++;
}
finally{
System.out.println("Executing " + Thread.currentThread().getName() + ":" + " Counter value: " + cnt);
l.unlock();
}
}
}
Output:
Call executeTask to increment the counter: Thread 1
Call executeTask to increment the counter: Thread 0
Call executeTask to increment the counter: Thread 2
Executing Thread 1: Counter value: 1
Executing Thread 0: Counter value: 2
Running Thread 2: Counter value: 3