What are the different ways to create a thread in Java?
In Java, there are four main ways to create a thread:
1. Extending the Thread class
By extending the Thread class, we override the run() method and start the thread using start().
Example:
java
CopyEdit
class MyThread extends Thread {
public void run() {
System.out.println("Thread running: " + Thread.currentThread().getName());
public class ThreadExample {
public static void main(String[] args) {
MyThread t1 = new MyThread();
t1.start(); // Starts a new thread
Pros
✅ Simple to use
✅ Can directly access Thread methods
Cons
❌ Java doesn’t support multiple inheritance, so extending Thread prevents extending another class
2. Implementing the Runnable Interface
Instead of extending Thread, we implement Runnable and pass it to a Thread object.
Example:
java
CopyEdit
class MyRunnable implements Runnable {
public void run() {
System.out.println("Runnable thread running: " + Thread.currentThread().getName());
public class RunnableExample {
public static void main(String[] args) {
Thread t1 = new Thread(new MyRunnable());
t1.start();
Pros
✅ Allows extending another class
✅ Better separation of concerns
Cons
❌ Requires explicitly creating a Thread object
3. Using Callable and Future (for returning results)
Unlike Runnable, Callable returns a result and can throw checked exceptions. It is executed using
ExecutorService.
Example:
java
CopyEdit
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
class MyCallable implements Callable<String> {
public String call() throws Exception {
return "Callable executed by " + Thread.currentThread().getName();
public class CallableExample {
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(new MyCallable());
System.out.println(future.get()); // Blocks until result is available
executor.shutdown();
Pros
✅ Returns a result
✅ Supports checked exceptions
Cons
❌ Requires ExecutorService
❌ Uses Future.get(), which can block execution
4. Using ExecutorService (Recommended for Thread Pooling)
Instead of manually creating and managing threads, ExecutorService efficiently handles multiple
threads using a thread pool.
Example:
java
CopyEdit
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class MyTask implements Runnable {
public void run() {
System.out.println("Task executed by: " + Thread.currentThread().getName());
public class ExecutorExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(3); // Thread pool of size 3
for (int i = 0; i < 5; i++) {
executor.submit(new MyTask());
executor.shutdown(); // Shut down the executor
Pros
✅ Manages multiple threads efficiently
✅ Avoids manual thread creation overhead
✅ Allows reuse of threads
Cons
❌ Requires proper thread management (shutdown(), handling exceptions)
Which Approach Should You Use?
Method Best For
Extending
Simple tasks, quick prototyping
Thread
Implementing
Recommended for most use cases
Runnable
Using Callable &
When you need a return value or handle exceptions
Future
Method Best For
Using Best for handling multiple threads efficiently
ExecutorService
What is Atomicity?
Atomicity is one of the ACID (Atomicity, Consistency, Isolation, Durability)
properties in database transactions. It ensures that a transaction is all-or-nothing
—either all operations in a transaction are successfully completed, or none of
them are applied.
Key Concept of Atomicity
If a transaction has multiple operations, either all succeed or all fail.
If any part of the transaction fails, the database rolls back to its previous
state.
Example of Atomicity
Example 1: Bank Transfer
Imagine a money transfer from Account A to Account B:
1. Debit ₹1000 from Account A
2. Credit ₹1000 to Account B
✅ If both steps succeed → Transaction is committed.
❌ If one step fails (e.g., server crash, network issue) → Transaction is rolled back.
SQL Example
sql
CopyEdit
START TRANSACTION;
UPDATE accounts SET balance = balance - 1000 WHERE account_id = 1; -- Debit
₹1000
UPDATE accounts SET balance = balance + 1000 WHERE account_id = 2; -- Credit
₹1000
COMMIT; -- Save changes
If any update fails, we ROLLBACK to prevent an inconsistent state:
Method Best For
sql
CopyEdit
ROLLBACK; -- Undo all changes
Atomicity in REST APIs
In REST APIs, atomicity ensures that a request completes fully or fails without
partial updates.
Example: User Registration API
Steps in registering a user:
1. Insert user details in the database
2. Send a verification email
If step 2 fails, step 1 must be rolled back to maintain atomicity.
Spring Boot Example (Transactional Annotation)
In Java (Spring Boot), we use @Transactional to ensure atomicity:
java
CopyEdit
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Transactional
public void registerUser(User user) {
userRepository.save(user); // Step 1: Save user
sendVerificationEmail(user); // Step 2: Send email
If sendVerificationEmail(user) fails, the userRepository.save(user) is automatically
rolled back.
Why is Atomicity Important?
Method Best For
✅ Prevents Partial Updates – Avoids data corruption.
✅ Ensures Data Integrity – Transactions remain consistent.
✅ Improves Reliability – Database is never left in an incomplete state.
Would you like an example of atomicity in distributed transactions (e.g., using
Kafka or two-phase commit)? 🚀
4o
You said:
atomicity integer?
ChatGPT said:
What is Atomicity in the Context of Integers?
When discussing atomicity with integers, it usually refers to atomic operations on
integer variables in multithreaded programming. An atomic operation ensures
that an integer update (e.g., increment, decrement) is performed without
interruption by other threads.
Why is Atomicity Important for Integers?
In multithreading, if multiple threads modify a shared integer without atomicity,
race conditions may occur, leading to incorrect values.
Example of Non-Atomic Integer Increment (Race Condition)
java
CopyEdit
class Counter {
int count = 0;
void increment() {
count++; // Not atomic (read-modify-write cycle)
If two threads execute count++ simultaneously:
1. One thread reads count = 5, another also reads count = 5
2. Both increment to 6, but one overwrites the other
3. The expected result (7) is lost
Method Best For
💥 This is a race condition!
How to Ensure Atomicity for Integers?
1. Using synchronized Block (Ensures only one thread updates at a time)
java
CopyEdit
class Counter {
int count = 0;
synchronized void increment() {
count++;
✅ Ensures atomicity but can cause performance overhead due to locking.
2. Using AtomicInteger (Preferred for Performance)
Java provides AtomicInteger, which guarantees atomic updates without using
locks.
java
CopyEdit
import java.util.concurrent.atomic.AtomicInteger;
class Counter {
AtomicInteger count = new AtomicInteger(0);
void increment() {
count.incrementAndGet(); // Atomic operation
✅ Efficient & thread-safe
✅ No need for explicit synchronization
Method Best For
Atomic Integer Operations in Java
Method Description
Atomically increments and returns the new
incrementAndGet()
value
Atomically decrements and returns the new
decrementAndGet()
value
Atomically adds delta and returns the new
addAndGet(int delta)
value
compareAndSet(int expected, int
Updates value only if it matches expected
update)
Example: Compare-and-Swap (CAS)
java
CopyEdit
AtomicInteger atomicInt = new AtomicInteger(10);
boolean updated = atomicInt.compareAndSet(10, 20); // If 10, update to 20
✅ Ensures safe concurrent updates without using locks.
Summary
Atomicity ensures integer updates are done safely in multithreading.
Non-atomic updates (count++) can lead to race conditions.
Use synchronized (locks) or AtomicInteger (lock-free, efficient).
Difference Between ReentrantLock and synchronized in Java
Both ReentrantLock and synchronized are used for thread synchronization in Java,
but they have key differences in flexibility, performance, and control.
1. Overview
Feature synchronized ReentrantLock
Type Built-in Java Explicit Lock class
Method Best For
Feature synchronized ReentrantLock
keyword (java.util.concurrent.locks.ReentrantLock)
Flexibility Less flexible More flexible
No fairness
Fairness Supports fairness (First-Come-First-Serve)
control
Try-Lock
Not possible Possible (tryLock())
Mechanism
Interruptible
Not possible Possible (lockInterruptibly())
Locking
Condition Supports Condition for advanced
No support
Variables synchronization
Less overhead in
Performance Better for complex, high-concurrency scenarios
simple cases
2. synchronized - Built-in Lock Mechanism
The synchronized keyword provides automatic locking on objects or methods.
Example: Synchronized Method
java
CopyEdit
class Counter {
private int count = 0;
public synchronized void increment() { // Lock is acquired on this instance
count++;
Example: Synchronized Block
java
CopyEdit
class Counter {
private int count = 0;
Method Best For
private final Object lock = new Object();
public void increment() {
synchronized (lock) { // Lock is acquired on 'lock' object
count++;
✅ Advantages of synchronized
✔ Simple and easy to use
✔ Automatically releases lock after execution
❌ Limitations
Cannot attempt non-blocking locks (tryLock()).
No explicit lock control (no fairness or interrupt handling).
3. ReentrantLock - More Flexible Locking
ReentrantLock is a more advanced, flexible locking mechanism from
java.util.concurrent.locks.
Example: Using ReentrantLock
java
CopyEdit
import java.util.concurrent.locks.ReentrantLock;
class Counter {
private int count = 0;
private final ReentrantLock lock = new ReentrantLock();
public void increment() {
lock.lock(); // Acquire lock
try {
Method Best For
count++;
} finally {
lock.unlock(); // Always release lock
✅ Advantages of ReentrantLock
✔ Try-Lock Mechanism → Avoids deadlocks
✔ Interruptible Locks → Threads can be interrupted while waiting
✔ Supports Fairness → Ensures first-come-first-serve locking
✔ Multiple Conditions → More fine-grained synchronization
❌ Limitations
Must explicitly release the lock (unlock()).
More complex than synchronized.
4. Key Differences with Examples
🔹 1. Try-Lock Mechanism (tryLock())
With synchronized, a thread waits indefinitely for a lock.
With ReentrantLock, a thread can try to acquire a lock without blocking.
Example: Using tryLock() to Avoid Blocking
java
CopyEdit
if (lock.tryLock()) { // If lock is available, acquire it
try {
// Critical section
} finally {
lock.unlock(); // Release lock
} else {
System.out.println("Lock not available, do something else!");
}
Method Best For
✅ Prevents deadlocks by not blocking if the lock is unavailable.
🔹 2. Interruptible Locking (lockInterruptibly())
With synchronized, a thread cannot be interrupted while waiting for a lock.
With ReentrantLock, a waiting thread can be interrupted.
Example: Using lockInterruptibly()
java
CopyEdit
try {
lock.lockInterruptibly(); // Allows interruption
// Critical section
} catch (InterruptedException e) {
System.out.println("Thread interrupted while waiting for lock.");
} finally {
lock.unlock();
✅ Useful when handling timeouts or thread cancellation.
🔹 3. Fairness Policy (First-Come-First-Serve)
synchronized does not guarantee fairness.
ReentrantLock supports fairness when created with true.
Example: Fair Lock
java
CopyEdit
ReentrantLock fairLock = new ReentrantLock(true); // Fair lock (FIFO order)
✅ Ensures that threads get locks in the order they requested them.
5. When to Use What?
Use synchronized when... Use ReentrantLock when...
Simplicity is preferred. Advanced lock control is needed.
Method Best For
Use synchronized when... Use ReentrantLock when...
There’s no need for tryLock() or
You need tryLock() to avoid blocking.
interruptible locks.
First-Come-First-Serve fairness is
No fairness is required.
needed.
You need advanced Condition
No need for multiple condition variables.
objects.
6. Conclusion
For simple synchronization → synchronized is best.
For fine-grained control, fairness, or interruptible locks → ReentrantLock
is better
Thread States in Java (Lifecycle of a Thread)
In Java, a thread can exist in six different states as defined in the Thread.State
enumeration.
1. New (NEW)
Definition: A thread that has been created but has not started yet.
Example:
java
CopyEdit
Thread t = new Thread(() -> System.out.println("Hello"));
The thread t is in the NEW state because start() has not been called.
Method Best For
2. Runnable (RUNNABLE)
Definition: A thread that is ready to run and waiting for CPU time.
Example:
java
CopyEdit
t.start(); // Now thread moves to RUNNABLE state
The thread is not necessarily running; it depends on the OS thread scheduler.
3. Blocked (BLOCKED)
Definition: A thread is waiting to acquire a lock (due to synchronized).
Example:
java
CopyEdit
class SharedResource {
synchronized void method() {
System.out.println(Thread.currentThread().getName() + " is running");
SharedResource resource = new SharedResource();
Thread t1 = new Thread(() -> resource.method());
Thread t2 = new Thread(() -> resource.method());
t1.start();
t2.start(); // If t1 has the lock, t2 moves to BLOCKED state.
✅ Occurs when one thread has a lock, and others are waiting for it.
4. Waiting (WAITING)
Definition: A thread is waiting indefinitely for another thread to notify it.
Example:
Method Best For
java
CopyEdit
class Example {
synchronized void waitForSignal() throws InterruptedException {
wait(); // Moves thread to WAITING state
synchronized void sendSignal() {
notify(); // Wakes up a waiting thread
✅ Must be notified using notify() or notifyAll().
5. Timed Waiting (TIMED_WAITING)
Definition: A thread is waiting for a specific time period (e.g., sleep(), join(),
wait(timeout)).
Example:
java
CopyEdit
Thread.sleep(2000); // Thread enters TIMED_WAITING for 2 seconds
✅ Automatically moves back to RUNNABLE when time expires.
6. Terminated (TERMINATED)
Definition: A thread has finished execution or was stopped unexpectedly.
Example:
java
CopyEdit
Thread t = new Thread(() -> System.out.println("Done!"));
t.start();
t.join(); // Ensures thread completes execution
Method Best For
System.out.println(t.getState()); // TERMINATED
Thread Lifecycle Diagram
sql
CopyEdit
NEW → RUNNABLE → BLOCKED / WAITING / TIMED_WAITING → TERMINATED
Summary of Java Thread States
State Occurs When... How to Move Out?
NEW Thread is created but not started. Call start().
RUNNABLE Ready to run, waiting for CPU time. OS scheduler selects it.
BLOCKED Waiting for a lock (synchronized). Lock is released.
notify() or join()
WAITING Waiting indefinitely (wait(), join()).
completes.
Waiting for a fixed time (sleep(),
TIMED_WAITING Time expires.
wait(timeout)).
TERMINATED Thread has finished execution. Cannot transition out.
Example: Get Current Thread State
java
CopyEdit
System.out.println(Thread.currentThread().getState());
Difference Between Thread.yield(), Thread.sleep(), and Thread.join() in Java
All three methods (yield(), sleep(), and join()) are used to control thread execution
but serve different purposes.
1. Thread.yield()
📌 Purpose: Suggests the thread scheduler to pause the current thread and allow
other threads to execute.
📌 Does it release CPU? ✅ Yes (but it's not guaranteed).
📌 Does it release locks? ❌ No.
Method Best For
Example
java
CopyEdit
class YieldExample extends Thread {
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " is running.");
Thread.yield(); // Suggest CPU to give other threads a chance
public class Main {
public static void main(String[] args) {
YieldExample t1 = new YieldExample();
YieldExample t2 = new YieldExample();
t1.start();
t2.start();
✅ Thread.yield() does not guarantee that another thread will run immediately. It
just hints the scheduler.
2. Thread.sleep(time)
📌 Purpose: Pauses the current thread for a specified time.
📌 Does it release CPU? ✅ Yes.
📌 Does it release locks? ❌ No.
Example
java
CopyEdit
Method Best For
class SleepExample extends Thread {
public void run() {
for (int i = 1; i <= 3; i++) {
try {
System.out.println(Thread.currentThread().getName() + " is sleeping for 2
seconds.");
Thread.sleep(2000); // Pause for 2 seconds
} catch (InterruptedException e) {
e.printStackTrace();
public class Main {
public static void main(String[] args) {
SleepExample t1 = new SleepExample();
t1.start();
✅ Thread.sleep(2000) pauses execution for 2 seconds, but the thread remains in
the TIMED_WAITING state.
3. Thread.join()
📌 Purpose: Makes the current thread wait until another thread finishes execution.
📌 Does it release CPU? ✅ Yes.
📌 Does it release locks? ❌ No.
Example
java
CopyEdit
class JoinExample extends Thread {
Method Best For
public void run() {
for (int i = 1; i <= 3; i++) {
System.out.println(Thread.currentThread().getName() + " is running.");
try {
Thread.sleep(1000); // Simulating work
} catch (InterruptedException e) {
e.printStackTrace();
public class Main {
public static void main(String[] args) throws InterruptedException {
JoinExample t1 = new JoinExample();
t1.start();
t1.join(); // Main thread waits for t1 to finish
System.out.println("Main thread continues after t1 finishes.");
✅ t1.join(); ensures that the main thread waits until t1 finishes.
Summary of Differences
Releases Releases
Method Purpose Example Use Case
CPU? Locks?
Suggests thread Useful when a thread has
scheduler to switch completed its important
yield() ✅ Yes ❌ No
execution to work but doesn't need CPU
another thread immediately.
Method Best For
Releases Releases
Method Purpose Example Use Case
CPU? Locks?
Pauses thread Useful for rate limiting,
sleep(time) execution for a ✅ Yes ❌ No waiting before retrying an
specified time operation.
Makes a thread Useful when one thread
wait until another must complete before
join() thread completes ✅ Yes ❌ No another continues (e.g.,
waiting for a background
task).
Types of Thread Pools in Java (ExecutorService)
Java provides different types of thread pools in the java.util.concurrent.Executors
class to manage multiple threads efficiently.
1. Fixed Thread Pool (newFixedThreadPool(n))
📌 Creates a pool of a fixed number of threads (n).
📌 If all threads are busy, new tasks wait in a queue.
Example
java
CopyEdit
import java.util.concurrent.*;
public class FixedThreadPoolExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(3); // Pool with 3
threads
for (int i = 1; i <= 5; i++) {
final int task = i;
executor.execute(() -> System.out.println("Executing Task " + task + " by " +
Method Best For
Thread.currentThread().getName()));
executor.shutdown(); // Shutdown after task completion
✅ Use Case: Suitable for applications with a fixed number of tasks, like web
servers.
2. Cached Thread Pool (newCachedThreadPool())
📌 Creates new threads as needed and reuses idle ones.
📌 If no threads are available, new ones are created.
📌 Threads are removed if idle for 60 seconds.
Example
java
CopyEdit
ExecutorService executor = Executors.newCachedThreadPool();
for (int i = 1; i <= 5; i++) {
final int task = i;
executor.execute(() -> System.out.println("Executing Task " + task + " by " +
Thread.currentThread().getName()));
executor.shutdown();
✅ Use Case: Good for applications with many short-lived tasks, like handling many
small API requests.
3. Single Thread Pool (newSingleThreadExecutor())
📌 Creates a pool with only one thread.
📌 Tasks execute sequentially (one at a time).
Example
Method Best For
java
CopyEdit
ExecutorService executor = Executors.newSingleThreadExecutor();
for (int i = 1; i <= 3; i++) {
final int task = i;
executor.execute(() -> System.out.println("Executing Task " + task + " by " +
Thread.currentThread().getName()));
executor.shutdown();
✅ Use Case: Ensures task execution order (e.g., writing logs sequentially).
4. Scheduled Thread Pool (newScheduledThreadPool(n))
📌 Executes tasks at a fixed delay or periodically.
Example: Run Task After a Delay
java
CopyEdit
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
scheduler.schedule(() -> System.out.println("Task executed after 3 seconds"), 3,
TimeUnit.SECONDS);
scheduler.shutdown();
Example: Run Task Periodically
java
CopyEdit
scheduler.scheduleAtFixedRate(() -> System.out.println("Periodic Task"), 1, 2,
TimeUnit.SECONDS);
✅ Use Case: Best for scheduled tasks, like cron jobs or auto-backups.
Method Best For
5. Work-Stealing Pool (newWorkStealingPool(n)) (Java 8+)
📌 Creates a pool of n threads using a ForkJoinPool.
📌 Automatically manages task distribution across multiple CPU cores.
📌 Efficient for parallel processing.
Example
java
CopyEdit
ExecutorService executor = Executors.newWorkStealingPool();
for (int i = 1; i <= 5; i++) {
final int task = i;
executor.execute(() -> System.out.println("Executing Task " + task + " by " +
Thread.currentThread().getName()));
executor.shutdown();
✅ Use Case: Best for CPU-intensive tasks, like image processing or data analysis.
Summary of Thread Pools
Thread Pool Description Best Use Case
Fixed Thread A fixed number of threads Best for a known, constant
Pool (n). workload (e.g., web servers).
Cached Thread Creates new threads as Best for handling many small, short-
Pool needed, reuses idle ones. lived tasks (e.g., API requests).
Single Thread Best when tasks must be executed
Single-threaded execution.
Pool in order (e.g., logging).
Scheduled Runs tasks after a delay or at Best for periodic tasks (e.g.,
Thread Pool fixed intervals. backups, cron jobs).
Work-Stealing Uses ForkJoinPool for Best for CPU-intensive tasks (e.g.,
Pool parallel processing. image processing).
How to Handle Deadlock in Java?
Method Best For
A deadlock occurs when two or more threads are waiting for each other to release
locks, causing an infinite wait. Here are different strategies to prevent and resolve
deadlocks.
1. Lock Ordering (Avoid Circular Wait) ✅
📌 Ensure that all threads acquire locks in the same order.
Example Without Lock Ordering (Deadlock Scenario) ❌
java
CopyEdit
class A {
synchronized void methodA(B b) {
System.out.println(Thread.currentThread().getName() + " locked A, waiting for
B");
synchronized (b) {
System.out.println(Thread.currentThread().getName() + " locked B");
class B {
synchronized void methodB(A a) {
System.out.println(Thread.currentThread().getName() + " locked B, waiting for
A");
synchronized (a) {
System.out.println(Thread.currentThread().getName() + " locked A");
🚨 Issue:
Thread-1 locks A and waits for B.
Thread-2 locks B and waits for A.
Method Best For
Deadlock occurs because both threads are waiting for each other.
✅ Corrected Version (Using Lock Ordering)
java
CopyEdit
class A {
synchronized void methodA(B b) {
synchronized (this) { // Lock A first
System.out.println(Thread.currentThread().getName() + " locked A");
synchronized (b) { // Then lock B
System.out.println(Thread.currentThread().getName() + " locked B");
✅ Fix: Always acquire locks in the same order (A → B).
2. Try-Lock with Timeout (Using ReentrantLock) ✅
📌 Instead of blocking forever, try acquiring a lock for a limited time.
Example
java
CopyEdit
import java.util.concurrent.locks.*;
class DeadlockAvoidance {
private final Lock lock1 = new ReentrantLock();
private final Lock lock2 = new ReentrantLock();
void process() {
Method Best For
try {
if (lock1.tryLock() && lock2.tryLock()) {
try {
System.out.println(Thread.currentThread().getName() + " acquired both
locks");
} finally {
lock2.unlock();
lock1.unlock();
} else {
System.out.println(Thread.currentThread().getName() + " could not
acquire locks, avoiding deadlock");
} finally {
if (lock1.isHeldByCurrentThread()) lock1.unlock();
if (lock2.isHeldByCurrentThread()) lock2.unlock();
public class Main {
public static void main(String[] args) {
DeadlockAvoidance obj = new DeadlockAvoidance();
new Thread(obj::process).start();
new Thread(obj::process).start();
✅ Fix: tryLock() prevents deadlock by failing gracefully if locks are unavailable.
3. Use a Single Lock Instead of Multiple Locks ✅
📌 Avoid using multiple locks if not necessary.
Method Best For
Example
java
CopyEdit
class SingleLockExample {
private final Object lock = new Object();
void process() {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + " acquired lock");
✅ Fix: Using a single lock prevents cyclic waiting.
4. Detect Deadlocks Using ThreadMXBean ✅
📌 Java provides ThreadMXBean to detect deadlocks at runtime.
Example
java
CopyEdit
import java.lang.management.*;
public class DeadlockDetector {
public static void main(String[] args) {
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
long[] deadlockedThreads = threadMXBean.findDeadlockedThreads();
if (deadlockedThreads != null) {
System.out.println("Deadlock detected in threads: " +
deadlockedThreads.length);
} else {
Method Best For
System.out.println("No deadlock detected.");
✅ Fix: Monitor and log deadlocks for debugging.
5. Break Deadlocks by Interrupting a Thread ✅
📌 Interrupt a thread if it holds a lock for too long.
Example
java
CopyEdit
class Task implements Runnable {
private final Object lock1;
private final Object lock2;
Task(Object lock1, Object lock2) {
this.lock1 = lock1;
this.lock2 = lock2;
public void run() {
try {
synchronized (lock1) {
Thread.sleep(50);
synchronized (lock2) {
System.out.println(Thread.currentThread().getName() + " acquired
locks");
} catch (InterruptedException e) {
Method Best For
System.out.println(Thread.currentThread().getName() + " interrupted to
prevent deadlock");
public class Main {
public static void main(String[] args) {
Object lockA = new Object();
Object lockB = new Object();
Thread t1 = new Thread(new Task(lockA, lockB));
Thread t2 = new Thread(new Task(lockB, lockA));
t1.start();
t2.start();
try {
Thread.sleep(100); // If deadlock happens, interrupt one thread
t1.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
✅ Fix: Interrupt the thread if it takes too long to acquire a lock.
Summary of Deadlock Prevention Strategies
Method How It Works Best Use Case
Lock Always acquire locks in a consistent order (e.g., Most effective
Method Best For
Method How It Works Best Use Case
when multiple locks
Ordering A → B)
are needed
Try-Lock with Use lock.tryLock(timeout) to fail gracefully if a Best for preventing
Timeout lock is unavailable long waits
Best when only one
Use a Single
Avoid multiple locks if possible shared resource is
Lock
involved
Detect Use ThreadMXBean.findDeadlockedThreads() Best for debugging
Deadlocks to monitor and debug in production
Interrupt Interrupt a thread if it takes too long to acquire Best for highly
Threads a lock responsive systems