Java Questions 1 - 10   «Prev  Next»

Thread Lifecycle and Coordination in Java SE 25

Learn what starts and ends a thread, how interruption and join differ, and how monitor waiting works. This set also reviews absolute and relative file paths.

  1. What happens if a Thread is created without a Runnable?

    Answer: new Thread() creates an unstarted platform thread with no Runnable target. Calling start starts it, but the base class's run implementation has no task to perform, so it returns. A subclass that overrides run can supply work without a separate Runnable.

    Constructing the object alone leaves it in NEW. Its task executes only after start, and the same object cannot be started again, even if its first execution did no work. Prefer an explicit Runnable when ordinary task execution is the intent; it makes the behavior easier to see.

  2. What is the difference between an absolute and a relative file path?

    Answer: An absolute path is complete according to its filesystem provider; a relative path needs a base directory. With the Windows default filesystem, C:\reports\result.txt is absolute, whereas reports\result.txt is relative. A drive-relative form such as C:result.txt is not the same as an absolute path.

    Use Path.of(...) and isAbsolute() rather than guessing from a string. toAbsolutePath() resolves a relative path against a default directory but does not prove the file exists. normalize() simplifies path components without accessing the filesystem; toRealPath() requires an existing path and, by default, resolves symbolic links.

  3. How should a running thread be asked to terminate?

    Answer: Design cooperative cancellation. A thread normally terminates when its run method returns or an uncaught exception ends execution. Calling interrupt() requests interruption; the task must respond by checking interruption or handling an interruptible blocking operation. It is not a forced kill.

    A volatile cancellation flag can provide visibility but cannot by itself wake a blocked operation. Future.cancel(true) can request interruption, while executor shutdown policies control task acceptance and cancellation attempts. None guarantees that arbitrary code stops immediately. In Java SE 25, the obsolete Thread.stop() throws UnsupportedOperationException.

    join() does not terminate another thread: it waits for that thread to finish. Choose a cancellation protocol first, then join if the caller needs to wait for completion.

  4. Does starting threads in a particular order guarantee their execution order?

    Answer: No. Start order, first execution, and completion order are different events. A thread started second may finish first, and multiple threads may execute at once. Priority does not make a particular order reliable.

    If a requirement says “finish A before beginning B,” represent that dependency explicitly. Start A and join it before starting B, or use an appropriate task-completion abstraction. Adding a sleep to B creates only a timing assumption; it fails when A takes longer than expected.

  5. How can one task wait until another thread finishes?

    Answer: Call join on the thread whose termination is required. The calling thread waits; the target thread continues its work. A successful untimed join establishes visibility of the completed thread's actions. Timed joins require checking whether the target actually finished.

    public class JoiningThreads {
        public static void main(String[] args) throws InterruptedException {
            Thread first = new Thread(() -> System.out.println("First finished"));
            Thread second = new Thread(() -> System.out.println("Second started"));
            first.start();
            first.join();
            second.start();
            second.join();
        }
    }

    The first line always precedes the second. The example declares InterruptedException so interruption of the waiting main thread is not silently swallowed. In application code, propagate interruption or restore the interrupt status and exit the operation when propagation is not possible.

  6. What does it mean for a thread to be dead?

    Answer: The API term is TERMINATED: the thread has completed execution. Its Thread object may still exist and can be inspected, but it no longer runs. isAlive() returns false both before a thread starts and after it terminates, so false alone does not distinguish NEW from TERMINATED.

    Garbage collection of the Thread object is a separate matter from termination. A retained reference keeps the object reachable, but does not keep a completed execution alive. Create a new Thread or submit a new task when more work is required.

  7. Can a terminated thread be restarted?

    Answer: No. A Thread object can be started at most once. This applies to both platform and virtual threads. To perform work again, create another Thread, or use an executor to run a new task submission.

    A Runnable may be reusable if its state and design allow it; the restriction concerns the Thread object's lifecycle. If repeated work is periodic, a scheduled executor may express the requirement more clearly than manually creating a thread for each interval.

  8. What happens when start is called twice on the same Thread?

    Answer: The second call throws IllegalThreadStateException, whether the first execution is still running or has already terminated. Waiting for the first execution with join does not reset the object to NEW.

    Calling run directly does not restart the thread either. For an ordinary Thread with a Runnable target, a direct run call is a method invocation on the calling thread. It does not recreate the original thread's independent execution or its start-related memory-ordering guarantees.

  9. Can more than one thread be RUNNABLE at the same time?

    Answer: Yes. RUNNABLE includes a thread executing in the JVM and one eligible for execution but waiting for processor or other operating-system resources. Java has no separate RUNNING enum constant. Many threads can be RUNNABLE, and multiple processors can execute different threads simultaneously.

    Virtual threads add another scheduling layer, so their Java state should not be treated as a direct operating-system thread state. getState() is a monitoring snapshot, not a coordination primitive. Use locks, latches, joins, or other documented mechanisms to synchronize work.

  10. Where are wait, notify, and notifyAll defined, and what do they require?

    Answer: They are methods of Object, not methods declared by Runnable. The current thread must own the target object's monitor, normally by entering a synchronized block on that same object. Otherwise the operation throws IllegalMonitorStateException.

    Wait releases that monitor and suspends the caller until an appropriate wakeup; before returning it reacquires the monitor. Always test the condition in a loop because wakeups can be spurious or another thread can consume the condition first. Notify selects one waiter and notifyAll signals all waiters, but neither releases the notifier's lock. Wait can throw checked InterruptedException; notify and notifyAll do not declare it.

References: Thread lifecycle and interruption, Path, and Object monitor methods.

SEMrush Software