Week 66 — What is the purpose of the class `Lock` (in package `java.util.concurrent.locks`)?

Question of the Week #66
What is the purpose of the class Lock (in package java.util.concurrent.locks)?
3 Replies
MrMisha | Coder
The interface Lock can be used to limit concurrency. Threads can acquire locks and later release them. Locks can be acquired using the lock() method and released with unlock(). A try-finally block should be used to ensure unlock is called when the work using the lock is finished:
Lock lock = getLock();
lock.lock();//starting here, other threads need to wait when they want to acquire the lock
try{
//do something
}finally{
lock.unlock();//allow other threads to acquire the lock again
}
Lock lock = getLock();
lock.lock();//starting here, other threads need to wait when they want to acquire the lock
try{
//do something
}finally{
lock.unlock();//allow other threads to acquire the lock again
}
One important implementation of this class is ReentrantLock which allows a thread to acquire the same lock multiple times but other threads cannot use it during that time:
private final Lock lock = new ReentrantLock();

void doSomething(){
lock.lock();//starting here, other threads need to wait when they want to acquire the lock
try{
otherMethod();
}finally{
lock.unlock();//allow other threads to acquire the lock again
}
}
void otherMethod(){
lock.lock();//this works even if the lock is already acquired by the current thread
try{
//some work here
}finally{
lock.unlock();//if the current thread had this lock before, other threads still won't be able to acquire this lock until unlock() is called again
}
}
private final Lock lock = new ReentrantLock();

void doSomething(){
lock.lock();//starting here, other threads need to wait when they want to acquire the lock
try{
otherMethod();
}finally{
lock.unlock();//allow other threads to acquire the lock again
}
}
void otherMethod(){
lock.lock();//this works even if the lock is already acquired by the current thread
try{
//some work here
}finally{
lock.unlock();//if the current thread had this lock before, other threads still won't be able to acquire this lock until unlock() is called again
}
}
MrMisha | Coder
It is also possible to create Conditions from a Lock that allow waiting until they are told to continue execution by another thread. Waiting for a condition can be done using the Condition#await method which releases the lock, waits until another thread calls signal() on that Condition acquires the lock again.
private final Lock lock = new ReentrantLock();
private final Condition someCondition = lock.newCondition();

void waitOnCondition() throws InterruptedException {
lock.lock();
try{
System.out.println("waiting");
someCondition.await();//wait until another thread calls signal()
System.out.println("no longer waiting");
}finally{
lock.unlock();
}
}
void wakeUp(){
lock.lock();
try{
System.out.println("sending signal");
someCondition.signal();//wake up one thread waiting on the condition
}finally{
lock.unlock();
}
}

void createWaitingAndNotifierThread(){
new Thread(()->{
try{
waitOnCondition();
}catch(InterruptedException e){
Thread.currentThread().interrupt();
}
}).start();
new Thread(()->{//wake up the first thread after one second
try{
Thread.sleep(1_000);
wakeUp();
}catch(InterruptedException e){
Thread.currentThread().interrupt();
}
}).start();
}
private final Lock lock = new ReentrantLock();
private final Condition someCondition = lock.newCondition();

void waitOnCondition() throws InterruptedException {
lock.lock();
try{
System.out.println("waiting");
someCondition.await();//wait until another thread calls signal()
System.out.println("no longer waiting");
}finally{
lock.unlock();
}
}
void wakeUp(){
lock.lock();
try{
System.out.println("sending signal");
someCondition.signal();//wake up one thread waiting on the condition
}finally{
lock.unlock();
}
}

void createWaitingAndNotifierThread(){
new Thread(()->{
try{
waitOnCondition();
}catch(InterruptedException e){
Thread.currentThread().interrupt();
}
}).start();
new Thread(()->{//wake up the first thread after one second
try{
Thread.sleep(1_000);
wakeUp();
}catch(InterruptedException e){
Thread.currentThread().interrupt();
}
}).start();
}
It is possible to have multiple Conditions for the same Lock.
📖 Sample answer from dan1st
MrMisha | Coder
"Lock" is an interface which locks concurrent access to a shared resource. At all it's used for a safe sync modification of objects. All code handled by lock should be covered with try-finally block. Someone prefers to use synchronized blocks, but locks are better, (personal opinion anyways) because you can actually use sync parted in a method. Also there's an ability to do a "test lock". We can execute tryLock() method to prevent locking method while it's used by another thread.
public class LockExample {
ReentrantLock lock = new ReentrantLock();
ArrayList<String> arrayList = new ArrayList<>();

public void test() {
lock.lock();

try {
arrayList.add("i added this while being locked");
} finally {
lock.unlock();
}
}
}
public class LockExample {
ReentrantLock lock = new ReentrantLock();
ArrayList<String> arrayList = new ArrayList<>();

public void test() {
lock.lock();

try {
arrayList.add("i added this while being locked");
} finally {
lock.unlock();
}
}
}
Submission from desinger

Did you find this page helpful?