ReviseAlgo Logo

Multithreading

Locks

Understand the Lock interface, ReentrantLock, lock timeouts, and fairness policies.

Interview: Tests comparison of Lock vs synchronized keyword, lock interruptibility, tryLock() usage, and unlocking best practices.

Last Updated: June 13, 2026 10 min read

The java.util.concurrent.locks.Lock interface provides more flexible and sophisticated locking operations than the synchronized keyword. It supports non-blocking lock attempts, lock timeouts, and lock interruptibility.

Core Idea

The Lock interface provides manual locking. ReentrantLock allows tryLock() timeout and lockInterruptibly().

Why It Matters

Using tryLock() allows threads to backtrack or try other tasks if a lock is held, preventing deadlocks.

Interview Lens

Requires writing structured lock-unlock logic (using try-finally) and explaining lock fairness side-effects.

Lock vs. Synchronized

Let's compare:

  • Explicit Release: Lock requires calling unlock() manually (typically inside a finally block). Synchronized releases locks automatically on scope exit.
  • Non-blocking Attempt: tryLock() attempts lock acquisition immediately and returns a boolean without blocking.
  • Fairness: ReentrantLock supports a fairness policy: fair locks grant the lock to the thread waiting longest, reducing starvation but lowering throughput.

Code Walkthrough

This class shows safe lock usage with try-finally and demonstrates tryLock with a timeout limit.

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.TimeUnit;

public class LockDemo { private final Lock lock = new ReentrantLock();

public void safeOperation() { lock.lock(); // Blocks until acquired try { // Modify shared state here } finally { lock.unlock(); // Always release in finally block! } }

public void tryOperationWithTimeout() { try { // Attempt to acquire lock for 1 second if (lock.tryLock(1, TimeUnit.SECONDS)) { try { System.out.println("Lock acquired!"); } finally { lock.unlock(); } } else { System.out.println("Could not acquire lock, performing backup task"); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }

Interview-Relevant Information

Q: What is the risk of enabling fairness (new ReentrantLock(true))?
Answer: Fair locks force threads requesting the lock to join a queue. This guarantees order and prevents thread starvation, but introduces scheduling overhead and context switching, significantly reducing throughput compared to default unfair locks.

Quick Checklist

Why must unlock() be inside finally? What does tryLock() return? When should you use fair locks? If yes, you understand ReentrantLock.

Use Cases

Acquiring locks with timeouts to prevent deadlocks in distributed data loaders.

Making resource checkouts interruptible in response to cancellation calls.

Common Mistakes

Calling unlock() outside of a finally block. If an exception occurs, the lock is never released, deadlocking the app.

Calling lock.unlock() when the thread does not hold the lock, throwing IllegalMonitorStateException.