This section is designed to kill the common doubts, traps, interview questions, and confusing points in Java Multithreading.
No.
Multiple processes execute independently.
Process 1
Process 2
Process 3
Multiple threads exist inside a process.
Process
|
┌────────┼────────┐
↓ ↓ ↓
Thread 1 Thread 2 Thread 3
Process = independent execution environment Thread = execution unit inside a process
❌ No.
A thread is a unit of execution within a process.
Process
|
├── Thread 1
├── Thread 2
└── Thread 3
The main() method itself is not a thread.
The JVM starts a main thread, and that thread invokes:
main(String[] args)So:
JVM
↓
Main Thread
↓
main()
❌ No.
Even a simple Java program starts with the main thread, and the JVM/runtime may have other threads as well.
Your application can additionally create many threads.
This is the #1 multithreading doubt.
t.start();Requests that the thread be started. The JVM then invokes run() on that new thread.
t.run();is simply a normal method call.
start()
↓
new thread execution
↓
run()
but:
run()
↓
normal method call
Example:
class Test extends Thread
{
public void run()
{
System.out.println(
Thread.currentThread().getName()
);
}
public static void main(String[] args)
{
Test t = new Test();
t.run();
}
}Output:
main
Why?
Because run() was directly invoked by the main thread.
class Test extends Thread
{
public void run()
{
System.out.println(
Thread.currentThread().getName()
);
}
public static void main(String[] args)
{
Test t = new Test();
t.start();
}
}The run() method executes on the newly started thread.
The exact thread name can vary, but it will not simply be the main thread.
❌ No.
t.start();
t.start();The second attempt throws:
java.lang.IllegalThreadStateException
A particular
Threadobject can be started only once.
Yes.
t.run();
t.run();There is no rule that prevents normal method invocation.
But remember:
Calling
run()directly does not create a new thread.
Not necessarily.
After:
t.start();the thread becomes eligible for scheduling.
The scheduler determines when it actually executes.
Therefore:
t.start();
System.out.println("Main");doesn't guarantee which message appears first.
Example:
class Test extends Thread
{
public void run()
{
for(int i = 1; i <= 5; i++)
System.out.println("Child " + i);
}
public static void main(String[] args)
{
Test t = new Test();
t.start();
for(int i = 1; i <= 5; i++)
System.out.println("Main " + i);
}
}One possible output:
Main 1
Child 1
Main 2
Child 2
Child 3
Main 3
Main 4
Child 4
Main 5
Child 5
Another run may produce a different order.
Because thread scheduling is not something you should use to assume a deterministic ordering unless you explicitly establish that ordering.
❌ Not necessarily.
Two related concepts are:
Multiple tasks make progress during overlapping periods.
Multiple tasks literally execute at the same time on different CPU cores.
Concurrency:
T1 → T2 → T1 → T2
Parallelism:
CPU 1 → T1
CPU 2 → T2
Multithreading can be used for concurrent execution and, where the runtime/OS and hardware allow it, parallel execution.
Generally, threads are lighter-weight than processes.
Threads within the same process can share process resources, while processes have stronger isolation.
But don't conclude:
"More threads always means more speed."
❌ Wrong.
Too many threads can cause:
- context-switch overhead
- memory overhead
- contention
- synchronization overhead
Suppose:
int count = 0;Two threads execute:
count++;You might expect:
Thread 1 → +1
Thread 2 → +1
Final = 2
But:
count++
is conceptually:
READ
↓
ADD
↓
WRITE
Possible interleaving:
T1 → reads 0
T2 → reads 0
T1 → writes 1
T2 → writes 1
Final:
1
instead of:
2
This is a race condition.
A critical section is a section of code that accesses shared state and therefore needs appropriate coordination when multiple threads can execute it concurrently.
Example:
synchronized
{
count++;
}Conceptually:
Thread 1 ──→ Critical Section
Thread 2 ──→ waits/competes
❌ No.
Only the relevant synchronized region protected by the same monitor is mutually exclusive.
Example:
Thread 1 → normal code ──→ synchronized section ──→ normal code
Thread 2 → normal code ──→ synchronized section ──→ normal code
Threads can still execute other independent work concurrently.
It provides mutual exclusion around the synchronized region for a particular monitor.
Example:
class Counter
{
int count;
synchronized void increment()
{
count++;
}
}For the same object:
Thread 1
↓
gets monitor
↓
increment()
↓
releases monitor
Thread 2
↓
gets monitor
↓
increment()
A monitor is the synchronization mechanism associated with an object/class that controls ownership of an intrinsic lock and supports wait()/notify() coordination.
Think:
Object
|
↓
Monitor / intrinsic lock
|
↓
one owner at a time
Every Java object can be used as the object associated with an intrinsic monitor for synchronization.
For example:
Object lock = new Object();
synchronized(lock)
{
// protected code
}The lock used here is associated with lock.
This wording causes confusion.
For an instance synchronized method:
synchronized void test()
{
}Java doesn't mean that the method itself is locked globally.
The object's monitor is acquired for the invocation.
Example:
static synchronized void test()
{
}The lock is associated with the Class object.
Conceptually:
Instance synchronized
↓
Object monitor
Static synchronized
↓
Class object's monitor
Suppose:
Counter c1 = new Counter();
Counter c2 = new Counter();Then:
c1 → monitor A
c2 → monitor B
If:
Thread 1 → c1 synchronized method
Thread 2 → c2 synchronized method
they don't automatically block one another merely because the methods have the same declaration.
❌ No.
This is a very important doubt.
synchronized(lock)
{
Thread.sleep(5000);
}During the sleep:
Thread → sleeping
↓
still owns monitor
So another thread requiring that same monitor can remain blocked.
✅ Yes.
synchronized(lock)
{
lock.wait();
}Conceptually:
Thread
↓
wait()
↓
releases lock
↓
WAITING
When later awakened, the thread must reacquire the monitor before continuing beyond the wait() call.
| Point | sleep() |
wait() |
|---|---|---|
| Class | Thread |
Object |
| Main purpose | Timed pause | Thread coordination |
| Releases monitor? | ❌ No | ✅ Yes |
| Monitor ownership required? | ❌ No | ✅ Yes |
| Can wait indefinitely? | No, ordinary sleep requires duration |
Yes |
| Can use timeout? | Yes | Yes |
Because the wait/notification mechanism is associated with an object's monitor.
Therefore:
obj.wait();
obj.notify();
obj.notifyAll();operate with respect to obj's monitor.
❌ Not arbitrarily.
This is incorrect:
lock.wait();if the current thread doesn't own lock's monitor.
Correct:
synchronized(lock)
{
lock.wait();
}Otherwise:
IllegalMonitorStateException
Yes.
Correct:
synchronized(lock)
{
lock.notify();
}The current thread must own the corresponding monitor.
❌ No.
notify() does not mean:
"Run this thread immediately."
It makes one waiting thread eligible to compete for the monitor.
The notifying thread still has to leave the synchronized region before another thread can acquire that monitor.
❌ No.
It wakes all threads waiting on that monitor in the sense that they become eligible to compete for the monitor.
Only one can own that monitor at a time.
notifyAll()
↓
T1 ─┐
T2 ─┼→ compete for monitor
T3 ─┘
↓
one acquires it
Correct:
synchronized(lock)
{
while(!condition)
{
lock.wait();
}
// use resource
}Not:
if(!condition)
{
lock.wait();
}Why?
Because after waking up, the thread should re-check the condition before proceeding.
Suppose:
Main
|
+── starts Thread T
|
+── join()
When main executes:
t.join();the main thread waits for t to terminate.
It is not the same thing as wait().
join() |
wait() |
|---|---|
Method of Thread |
Method of Object |
| Used to wait for a thread's termination | Used for coordination around a monitor |
| Calling thread waits for target thread | Current thread waits for notification/condition |
| Associated with target thread's completion | Associated with an object's monitor |
It enters:
TERMINATED
It cannot be restarted.
NEW
↓
start()
↓
RUNNABLE
↓
run() completes
↓
TERMINATED
❌ No.
t.start(); // first time
// after termination
t.start(); // IllegalThreadStateExceptionCreate another Thread object if you need another execution.
Deadlock occurs when threads are permanently waiting for locks/resources held by one another.
Example:
Thread 1
|
holds Lock A
|
waits for Lock B
↑
|
holds Lock B
|
Thread 2
|
waits for Lock A
Neither progresses.
A common strategy is to acquire multiple locks in a consistent global order.
For example:
Always acquire:
Lock A
↓
Lock B
Never:
Thread 1: A → B
Thread 2: B → A
This can eliminate one common circular-wait pattern.
Other approaches include minimizing lock scope and using higher-level concurrency utilities.
One thread keeps getting denied the resources/opportunities it needs.
T1 → repeatedly gets resource
T2 → repeatedly waits
Unlike deadlock, other threads may continue making progress.
Threads are not blocked, but continuously react to each other without completing useful work.
T1 → changes behavior
T2 → reacts
T1 → reacts
T2 → reacts
They are active but don't progress.
❌ No.
Primarily provides visibility and ordering guarantees for accesses to that variable.
Provides mutual exclusion and memory synchronization.
volatile
↓
visibility/order
synchronized
↓
mutual exclusion
+
visibility/order
❌ No.
volatile int count;
count++;count++ is a read-modify-write operation.
volatile doesn't turn it into one indivisible atomic operation.
Use an appropriate atomic class or synchronization when atomic increment is required.
AtomicInteger count = new AtomicInteger();
count.incrementAndGet();It provides atomic operations without requiring you to synchronize that increment yourself.
Common atomic classes include:
AtomicInteger
AtomicLong
AtomicBoolean
String is immutable.
Once a String object is created, its state cannot be changed.
This makes sharing String objects between threads much safer than sharing mutable objects.
But thread safety of an application still depends on the overall shared state, not simply whether one field happens to be a String.
❌ No.
StringBuilder is designed for efficient single-threaded use.
For shared mutable text state across threads, you need appropriate external synchronization or a suitable concurrent design.
StringBuffer has synchronized methods and is designed for thread-safe operations on the buffer itself.
But remember:
Thread-safe individual operations don't automatically make an entire multi-step algorithm thread-safe.
Yes.
class Demo extends Thread
{
public void run()
{
System.out.println("Running");
}
public static void main(String[] args)
{
Demo t1 = new Demo();
Demo t2 = new Demo();
Demo t3 = new Demo();
t1.start();
t2.start();
t3.start();
}
}Demo
|
├── t1
├── t2
└── t3
Each is a separate Thread object.
Yes.
class Task implements Runnable
{
public void run()
{
System.out.println("Task");
}
}
class Demo
{
public static void main(String[] args)
{
Task task = new Task();
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start();
t2.start();
}
}Here both threads execute the same Runnable object's run() method.
If that object contains mutable shared state, synchronization may be necessary.
Thread |
Runnable |
|---|---|
| Represents a thread | Represents a task |
| Class is extended | Interface is implemented |
Uses start() on Thread object |
Create a Thread with Runnable |
| Prevents extending another class | Class can still extend another class |
This is one reason Runnable is often preferable when modeling a task separately from the thread executing it.
A daemon thread is a background thread.
Thread t = new Thread(task);
t.setDaemon(true);
t.start();Important:
setDaemon(true)
↓
BEFORE start()
The JVM does not remain alive solely because daemon threads remain after all non-daemon threads have terminated.
Java provides:
MIN_PRIORITY = 1
NORM_PRIORITY = 5
MAX_PRIORITY = 10
Example:
t.setPriority(Thread.MAX_PRIORITY);Does maximum priority guarantee first execution?
❌ No.
Never use priority as a substitute for proper synchronization or coordination.
Instead of manually creating a thread for every task:
1000 tasks
↓
1000 threads
you can use a thread pool:
1000 tasks
↓
ExecutorService
↓
Thread Pool
↓
Fixed number of workers
Example:
ExecutorService service =
Executors.newFixedThreadPool(3);Then:
service.submit(task);It can:
- reuse worker threads
- control the number of concurrent tasks
- reduce thread-creation overhead
- provide task management
And after submitting work:
service.shutdown();should be used when you no longer need the executor to accept new tasks.
Runnable r = () ->
{
System.out.println("Hello");
};Primarily represents work with no returned result.
Callable<Integer> c = () ->
{
return 100;
};Can return a result and throw checked exceptions.
Future<Integer> f =
service.submit(c);Later:
Integer result = f.get();get() waits if the computation isn't finished yet.
So:
Callable
↓
ExecutorService
↓
Future
↓
get()
↓
Result
synchronized void method()
{
}lock every object of that class?
❌ No.
It synchronizes on the particular object on which the instance method is invoked.
For:
A a1 = new A();
A a2 = new A();conceptually:
a1 → Monitor 1
a2 → Monitor 2
Not exactly.
wait() is a coordination mechanism.
The thread:
wait()
↓
releases corresponding monitor
↓
waits
↓
gets notified / otherwise becomes eligible
↓
reacquires monitor
↓
continues
Not immediately.
The notifying thread still owns the monitor until it exits the synchronized region.
The waiting thread can proceed only after it successfully reacquires that monitor.
❌ No.
It temporarily places the thread into:
TIMED_WAITING
After the sleep period, it can become eligible to run again.
❌ No.
It makes the calling thread wait for the target thread to terminate.
Main → join(child)
↓
Main waits
Child → continues
↓
terminates
Main → continues
❌ No.
synchronized provides the required monitor-based mutual exclusion and memory synchronization, but you should not assume a particular fairness ordering between competing threads.
❌ Absolutely not guaranteed.
t1.start();
t2.start();
t3.start();does not establish:
t1
↓
t2
↓
t3
execution order.
If order matters, explicitly coordinate the threads using mechanisms such as join(), locks/conditions, executors, or other concurrency constructs.
| Doubt | Correct Answer |
|---|---|
Thread = process? |
❌ No |
main() itself = thread? |
❌ Main method runs on main thread |
start() creates/starts thread execution? |
✅ Yes |
run() directly creates a thread? |
❌ No |
Can start() be called twice? |
❌ No |
Can run() be called directly twice? |
✅ Yes, as normal method calls |
Does sleep() release monitor? |
❌ No |
Does wait() release corresponding monitor? |
✅ Yes |
Is wait() a Thread method? |
❌ Object method |
Is sleep() an Object method? |
❌ Thread method |
Does notify() immediately execute a waiting thread? |
❌ No |
Does notifyAll() execute all waiting threads simultaneously? |
❌ No |
Does synchronized make the whole program single-threaded? |
❌ No |
Does volatile make count++ atomic? |
❌ No |
| Does higher priority guarantee first execution? | ❌ No |
| Can different objects have different intrinsic monitors? | ✅ Yes |
Does instance synchronized use object monitor? |
✅ Yes |
Does static synchronized use Class object's monitor? |
✅ Yes |
| Can deadlock occur with multiple locks? | ✅ Yes |
| Is starvation the same as deadlock? | ❌ No |
| Is livelock the same as deadlock? | ❌ No |
Does join() make calling thread wait for target completion? |
✅ Yes |
| Can terminated Thread object be restarted? | ❌ No |
Is Runnable a thread itself? |
❌ It represents a task |
Is ExecutorService useful for managing tasks/threads? |
✅ Yes |
Whenever you see a multithreading question, mentally walk through this:
THREAD
↓
start()?
↓
run() executes
↓
Multiple threads running
↓
Shared data?
/ \
NO YES
↓ ↓
Usually Race condition?
↓
YES
↓
Critical section
↓
synchronized?
↓
Monitor
↓
Need communication?
/ \
YES NO
↓ ↓
wait() continue
↓
notify()
notifyAll()
Possible problems
↓
┌────────────┼────────────┐
↓ ↓ ↓
Deadlock Starvation Livelock
start()starts thread execution;run()is the task.
sleep()pauses but does not release the monitor.
wait()waits and releases the corresponding monitor.
synchronizedprotects shared critical sections using monitors.
Multithreading gives concurrency, but correctness requires proper coordination of shared state.