Detailed explanation
Multithreading allows multiple threads of execution within one Java process. Threads share heap objects but have separate call stacks, so they can work on related data independently. Concurrency means tasks make progress during overlapping periods; parallelism means tasks actually execute simultaneously on different CPU cores. Multithreading helps keep applications responsive and overlap waiting operations, such as network calls, with other work. However, shared mutable data introduces race conditions and visibility problems, requiring coordination through tools such as synchronized, locks, atomic classes, or concurrent collections.
Java officially defines six states in Thread.State: NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, and TERMINATED. NEW means a Thread object exists but start() has not been called. Calling start() schedules independent execution of its run() method and makes it RUNNABLE. Java's RUNNABLE state includes both executing and ready-to-execute threads; RUNNING is a useful conceptual description, not a separate Java enum value. The scheduler determines when runnable threads receive CPU time, so calling start() does not guarantee immediate execution.
BLOCKED specifically means waiting to acquire an intrinsic monitor lock, usually when entering synchronized code. WAITING means waiting indefinitely for another action, for example through Object.wait() or Thread.join() without a timeout. TIMED_WAITING occurs with operations such as Thread.sleep(), timed wait(), or timed join(). Object.wait() releases the monitor on which it is called; sleep() does not release held monitors. After notification, a waiting thread must reacquire that monitor before wait() returns, potentially entering BLOCKED first. A thread becomes TERMINATED when run() finishes normally or exits because of an uncaught exception. A terminated thread cannot be restarted.
You can extend Thread or pass a Runnable to a Thread constructor, as in new Thread(() -> System.out.println("running")). Calling start() launches the thread; calling run() directly executes synchronously on the caller's thread. Callable represents a task that returns a result and may throw checked exceptions; it is commonly submitted to an ExecutorService rather than passed directly to Thread. For application task management, prefer executors to separate tasks from scheduling and lifecycle management, and shut them down appropriately. Interviewers look for precise state definitions, realistic transitions, and awareness that concurrency requires correctness as well as performance.
Key points to remember
- Threads share heap data but maintain separate call stacks.
- Java has six official thread states; RUNNING is included within RUNNABLE.
- start() enables independent execution; run() alone is an ordinary method call.
- BLOCKED means intrinsic monitor contention; WAITING and TIMED_WAITING describe different waiting conditions.
- Use Runnable for tasks without results, Callable for result-bearing tasks, and ExecutorService for task management.
Common mistakes candidates make
- Listing RUNNING as an official Thread.State or treating every kind of waiting as BLOCKED.
- Calling run() instead of start(), or attempting to start the same Thread instance twice.
- Assuming sleep() releases locks or that notification immediately lets a waiting thread continue.
Likely follow-up questions
What happens if start() is called twice on the same thread?
The second call throws IllegalThreadStateException, even if the thread has already terminated. Create a new Thread instance or submit another task to an executor instead.
How do wait() and sleep() differ?
Object.wait() requires ownership of the object's monitor and releases that monitor while waiting. Thread.sleep() pauses the current thread without releasing held monitors and does not require monitor ownership.
Why prefer ExecutorService over manually creating threads?
ExecutorService separates task submission from execution policy and provides lifecycle control; pool-based implementations can reuse worker threads. Submitting a Callable returns a Future through which the caller can retrieve its result or observe execution failure.
Interview tip: Explain the six official states first, trace one thread from construction to termination, and then distinguish start() from run() and wait() from sleep().
