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
Eric McIntyre
Eric McIntyre9mo ago
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
}
}
Eric McIntyre
Eric McIntyre9mo ago
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
Eric McIntyre
Eric McIntyre9mo ago
"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
Want results from more Discord servers?
Add your server