Interview Questions 1 - 10  «Prev Next»

Java SE 25: Waiting, Sleeping, and Runnable Tasks

Learn monitor waiting, interruption, thread scheduling, and the difference between running a task directly and starting a new Java thread.

  1. What does Thread.sleep() do?

    Answer: It pauses the currently executing thread for a requested duration, subject to timer accuracy and scheduling. It does not release monitors the thread holds. Interruption can end the sleep by throwing InterruptedException; the interrupted status is cleared when that exception is thrown.

    Do not use sleep to prove that another thread has finished or that a shared write is visible. Use completion and coordination mechanisms for those requirements. Scheduling delays mean it is not a precise clock.

  2. What happens when Object.wait() is called?

    Answer: The caller must own that object's monitor. Wait releases that monitor while the thread waits, and the thread must reacquire it before returning. Other monitors held by the thread remain held. Calling wait without ownership throws IllegalMonitorStateException.

    Wait declares InterruptedException, not IOException. Check the condition in a while loop, because wakeups do not guarantee that the condition is true.

  3. Why are wait(), notify(), and notifyAll() defined on Object?

    Answer: Every object has an associated monitor and wait set. These methods coordinate threads around that object's monitor. Notify selects an arbitrary waiter, while notifyAll awakens all waiters; awakened threads still compete to reacquire the monitor.

    A notification does not immediately transfer ownership or store a durable signal for future waiters. The shared condition carries the meaning, and both the condition and its notification must follow the same synchronization protocol.

  4. Why are wait() and sleep() separate methods?

    Answer: They solve different problems. Sleep is a timed pause of the current thread and keeps held monitors. Wait is condition coordination on an owned monitor and releases that monitor temporarily. Wait may be timed or untimed; neither guarantees an immediate return to execution once eligible.

  5. What can cause wait() to finish waiting?

    Answer: Notification, interruption, a timeout for a timed wait, or a spurious wakeup can end waiting. The thread must still reacquire the monitor. Interruption is reported with InterruptedException rather than a normal successful return.

    public class MonitorCondition {
        static final class Gate {
            private boolean ready;
            synchronized void awaitReady() throws InterruptedException {
                while (!ready) { wait(); }
            }
            synchronized void open() {
                ready = true;
                notifyAll();
            }
        }
        public static void main(String[] args) throws InterruptedException {
            Gate gate = new Gate();
            Thread worker = Thread.ofVirtual().start(() -> {
                try {
                    gate.awaitReady();
                    System.out.println("Ready");
                } catch (InterruptedException exception) {
                    Thread.currentThread().interrupt();
                }
            });
            gate.open();
            worker.join();
        }
    }
    

    The example works even if open happens before the worker starts waiting: ready records the condition. Higher-level tools such as CountDownLatch often express one-time signaling more directly.

  6. What is IOException, and how is it handled?

    Answer: IOException is a checked exception class describing I/O failures, not a method. Code that can throw it must catch it or declare it as required by the compiler. Use try-with-resources to close compatible resources even when an operation fails.

    Handle or propagate the specific failure meaningfully. An empty catch block hides problems; replacing an interruption exception with IOException also confuses distinct failure mechanisms.

  7. How do Thread and Runnable differ?

    Answer: Runnable describes a task through its void run method. Thread represents a thread of execution and its lifecycle. Pass a Runnable to a thread builder or executor to separate work from how it is scheduled. A Runnable can also be invoked directly without creating a thread.

  8. How do threads enable concurrent or asynchronous work?

    Answer: Threads allow work to progress independently. Multiple cores may execute tasks in parallel, and a scheduler can interleave them on fewer cores. Starting work asynchronously means the caller can continue before it completes; it does not remove the need to coordinate shared state or observe failures.

    Virtual threads make many blocking tasks cheaper to represent, but they do not make CPU-intensive work run faster than the available processors or eliminate limits of downstream resources.

  9. What is a Runnable argument?

    Answer: It is a value passed to a parameter of type Runnable, often a lambda or an instance implementing run. For example, Thread.ofVirtual().start(() -> doWork()) receives a task to execute. The task can capture final or effectively final local variables, but captured objects can still be mutable.

  10. Does calling run() start a new thread?

    Answer: No. Calling a Runnable's run method directly executes on the calling thread. Starting a Thread, or submitting a task to an executor, supplies the scheduling behavior. A Thread can be started only once. Runnable.run does not declare checked exceptions, so a task must handle them or use an appropriate result-bearing abstraction such as Callable.

References: Object, Thread, Runnable, CountDownLatch, IOException.


SEMrush Software