-
Notifications
You must be signed in to change notification settings - Fork 0
Java Interview Treads, Exceptions
Yash edited this page Feb 12, 2026
·
2 revisions
Thread: Group of statements that are executed separately. Thread is a "light weight processor" which share common features of a processor.
ThreadCls t = new ThreadCls();
t.run(); // normal function call
t.start(); // Starts new Thread
t.start(); // java.lang.IllegalThreadStateException- Why use Runnable when Thread is already available?
- Java does not support multiple inheritance (a class cannot extend more than one class).
- If we extend the Thread class, we cannot extend any other class.
- But if we implement the Runnable interface, we are still free to extend another class.
Class MyClass extends Thread {} // Now this class cannot extend any other class.
Class MyClass extends Thread, SuperClass {} // {WRONG} ❌ multiple inheritance not possible
Class MyClass extends SuperClass implements Runnable {} // MyTask can still extend another class if needed.Thread Example with DeadLock and Precautions to avoid it
| Source | Deadlock | Avoid Deadlock |
|---|---|---|
NEW → RUNNABLE → RUNNING → TERMINATED
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
public class Thread implements Runnable {
private volatile int threadStatus; // default indicates thread 'not yet started'
public static native void sleep(long millis) throws InterruptedException;
private native void start0();
/* Causes this thread to begin execution; the Java Virtual Machinecalls the run method of this thread.
* It is never legal to start a thread more than once.In particular,
* a thread may not be restarted once it has completedexecution. */
public synchronized void start() {
// A zero status value corresponds to state "NEW".
if (threadStatus != 0)
throw new IllegalThreadStateException();
// Notify the group that this thread is about to be started
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
}
|
public class DeadlockExample {
private static final Object firstLock = new Object();
private static final Object secondLock = new Object();
// Method 1: Extending Thread class
private static class MyThread extends Thread {
public void run() {
System.out.println(Thread.currentThread().getName() + " started...");
synchronized (firstLock) {
System.out.println(Thread.currentThread().getName() + " Holding lock 1...");
try { Thread.sleep(100); } catch (InterruptedException e) {}
System.out.println(Thread.currentThread().getName() + " Waiting for lock 2...");
synchronized (secondLock) {
System.out.println(Thread.currentThread().getName() + " Holding lock 1 & 2...");
}
}
System.out.println(Thread.currentThread().getName() + " ended.");
}
}
// Method 2: Implementing Runnable interface (preferred)
private static class MyRunnable implements Runnable {
public void run() {
System.out.println(Thread.currentThread().getName() + " started...");
synchronized (secondLock) {
System.out.println(Thread.currentThread().getName() + " Holding lock 2...");
try { Thread.sleep(100); } catch (InterruptedException e) {}
System.out.println(Thread.currentThread().getName() + " Waiting for lock 1...");
synchronized (firstLock) {
System.out.println(Thread.currentThread().getName() + " Holding lock 1 & 2...");
}
}
System.out.println(Thread.currentThread().getName() + " ended.");
}
}
}
Example: public static void main(String args[])
// Using Thread class
MyThread t1 = new MyThread(); // Lock1, Lock2
t1.start();
MyRunnable t2 = new MyRunnable(); // Lock2, Lock1
new Thread(t2).start();
//
// Thread lifecycle : NEW → RUNNABLE → RUNNING → TERMINATED
MyThread t11 = new MyThread();
t11.start(); // ✅ First time – works fine : on start() it moves from NEW to RUNNABLE/RUNNING state.
// 🚫 A terminated thread cannot go back to NEW state.
try { Thread.sleep(10000); } catch (InterruptedException e) {}
t11.start(); // ❌ Second time – throws exception ❌ IllegalThreadStateException.
//
// Avoid Deadlock: Lock Ordering (Most Common)
// Always acquire locks in the same order across all threads: Locks synchronized (firstLock) then synchronized (secondLock)
// Different Objects Thread start no problem
new MyThread().start(); // new object ✅ First time – works fine
new MyThread().start(); // new object ✅ First time – works fine DeadLock
// Runnable : no dead-lock. Both start at same time but one thread acquires the lock others wait (Lock2)
MyRunnable t22 = new MyRunnable();
new Thread(t22).start();
new Thread(t22).start();
|
Maintain Same Lock Ordering: Always acquire locks in a consistent global order
Both threads follow the same order → no circular waiting → no deadlock. (firstLock → secondLock)
Runnable task = () -> {
synchronized (firstLock) {
System.out.println(Thread.currentThread().getName() + " holding firstLock");
//
try { Thread.sleep(100); } catch (InterruptedException e) {}
//
synchronized (secondLock) {
System.out.println(Thread.currentThread().getName() + " holding lock1 & secondLock");
}
}
};
Thread thread1 = new Thread(() -> {
// Lock firstLock, do work, release
synchronized (firstLock) {
System.out.println("Thread 1: Working with Resource 1");
}
// Then lock secondLock
synchronized (secondLock) {
System.out.println("Thread 1: Working with Resource 2");
}
});
// Method 2: Implementing Runnable interface (preferred)
private static class MyRunnable implements Runnable {
public void run() {
System.out.println(Thread.currentThread().getName() + " started...");
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName() + " Waiting for lock 1...");
synchronized (firstLock) {
System.out.println(Thread.currentThread().getName() + " Holding lock 1...");
try { Thread.sleep(100); } catch (InterruptedException e) {}
}
System.out.println(Thread.currentThread().getName() + " Waiting for lock 2...");
synchronized (secondLock) {
System.out.println(Thread.currentThread().getName() + " Holding 2...");
try { Thread.sleep(100); } catch (InterruptedException e) {}
}
}
System.out.println(Thread.currentThread().getName() + " ended.");
}
}private static class MyRunnable implements Runnable {
public void run() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + " started...");
for (int i = 0; i < 3; i++) {
try {
// Try to acquire first lock
if (firstLock.tryLock(50, TimeUnit.MILLISECONDS)) {
try {
System.out.println(threadName + ": Acquired first lock");
// Try to acquire second lock
if (secondLock.tryLock(50, TimeUnit.MILLISECONDS)) {
try {
System.out.println(threadName + ": Acquired both locks!");
} finally {
secondLock.unlock();
}
}
} finally {
firstLock.unlock();
}
}
// If couldn't get both locks, retry
System.out.println(threadName + ": Couldn't acquire both locks, retrying...");
} catch (InterruptedException e) {
System.out.println("InterruptedException:"+ e.getMessage());
Thread.currentThread().interrupt();
}
}
System.out.println(Thread.currentThread().getName() + " ended.");
}
}Use Higher-Level Concurrency Utilities: Consider ExecutorService, ConcurrentHashMap, etc. Deadlock Detection: Use tools like JConsole or VisualVM to detect deadlocks in running applications |
| Thread States | State Transition Diagram |
|---|---|
NEW → RUNNABLE → RUNNING → TERMINATED
↕ ↕
BLOCKED WAITING/TIMED_WAITINGThread t = new Thread(); // NEW statet.start(); // Starts the thread (NEW → RUNNABLE)4. BLOCKED : Thread is waiting for a monitor lock. static final Object lock = new Object();
synchronized(lock) { // Another thread holds lock
// Waiting to enter - BLOCKED state
}lock.wait(); // WAITING - Object wait
Thread.join(); // WAITING - Wait for thread to die (RUNNING → WAITING)
LockSupport.park(); // WAITINGThread.sleep(1000); // TIMED_WAITING - Pauses thread for time(RUNNING → TIMED_WAITING)
lock.wait(1000); // TIMED_WAITING
Thread.join(1000); // TIMED_WAITING - Wait for thread with timeout(RUNNING → TIMED_WAITING)
lock.notify(); // ✅ Wake up one of the waiting threadNEW → RUNNABLE → (enters synchronized) → RUNNABLE → wait() → WAITING
↓ ↓
(notify called) (notify + lock available)
↓ ↓
BLOCKED (waiting to re-acquire lock) → (lock acquired) → RUNNABLE → TERMINATED❌ Problem : obj.notify() without synchronized block
// This throws IllegalMonitorStateException
obj.notify(); // ❌ WRONG - not in synchronized blocknotify() in synchronized block
synchronized(obj) {
obj.notify(); // ✅ CORRECT - inside synchronized block
}t.interrupt() instead of notify()
t.interrupt(); // This interrupts the thread, doesn't notify it properly
interrupt() vs notify() difference:
|
Golden Rule: Always acquire the monitor lock (using synchronized) before calling wait(), notify(), or notifyAll()!
child Thread = synchronized(obj) { lock.wait(); }
main Thread = synchronized(obj) { lock.notify(); }
public class ThreadLifecycleDemoComplete {
static final Object lock = new Object();
static volatile boolean dataReady = false;
public static void main(String[] args) throws InterruptedException {
// CHILD THREAD (Consumer)
Thread childThread = new Thread(() -> {
System.out.println("Child: Started | State: " + Thread.currentThread().getState());
try {
synchronized(lock) {
System.out.println("Child: Acquired lock");
while (!dataReady) {
System.out.println("Child: Data not ready, calling wait()");
System.out.println("Child: State before wait(): " + Thread.currentThread().getState());
lock.wait(); // WAITING state (releases lock)
System.out.println("Child: Woke up from wait()!");
}
System.out.println("Child: Data is ready! Processing...");
System.out.println("Child: State after wake up: " + Thread.currentThread().getState());
}
} catch (InterruptedException e) {
System.err.println("Child: Interrupted - " + e.getMessage());
}
System.out.println("Child: Finished");
}, "Child-Thread");
// MAIN THREAD (Producer)
System.out.println("Main: Child thread state: " + childThread.getState()); // NEW
childThread.start();
System.out.println("Main: Child thread state after start(): " + childThread.getState()); // RUNNABLE
Thread.sleep(1000); // Let child thread enter wait()
System.out.println("Main: Child thread state (in wait): " + childThread.getState()); // WAITING
// Prepare data
Thread.sleep(2000);
System.out.println("\nMain: Preparing data...");
dataReady = true;
// Notify the waiting thread
synchronized(lock) {
System.out.println("Main: Acquired lock");
System.out.println("Main: Calling notify()");
lock.notify(); // ✅ Wake up child thread
System.out.println("Main: notify() called");
System.out.println("Main: Child thread state (BLOCKED, waiting for lock): " + childThread.getState());
Thread.sleep(1000); // Hold lock
System.out.println("Main: Releasing lock...");
} // Lock released
System.out.println("Main: Lock released");
Thread.sleep(500);
System.out.println("Main: Child thread state (should be RUNNABLE): " + childThread.getState());
childThread.join();
System.out.println("Main: Child thread state (final): " + childThread.getState()); // TERMINATED
}
}
|
AI productivity tools: Apple’s Genius Plan to Win the AI Race (without building an AI model), Elon Musk’s Grok AI Empire
- Microsoft(PC's 49%) -> Azure Cloud -> Open AI
chatgpt - Google(Android) -> Google Cloud Platform -> Gemini
- Instagram/WhatsApp Meta Ai
- Elon Musk’s -> Colossus Datacenter -> GrokAI
blackbox.ai- Z AI