- Which statement correctly distinguishes the memory relationships?
Answer: The threads may share the List object on the heap while each keeps its own local variables; the separate process receives a copy of the data, not the original in-process reference.
Whenever you see a question about threads and processes in Java, anchor yourself to two fundamental memory boundaries: the stack vs. heap boundary within a JVM, and the process boundary between separate JVMs.
Within a single JVM, every thread gets its own private call stack. That means local primitive variables (like your int) live exclusively on the declaring thread's stack — no other thread can touch them. Heap-allocated objects, however, are shared across all threads in that JVM. When the main thread passes a List reference to the worker thread, both threads hold references pointing to the same List object on the heap. This is exactly what D describes, making it the correct answer: threads share the heap object while each retains private local variables. Critically, when data crosses a process boundary (a separate JVM), Java has no shared heap — the receiving process gets a copy of the serialized data, not the original reference or object identity.
A is wrong because threads absolutely do share the same heap — there is one heap per JVM, not one per thread. B is wrong on both counts: references are not "duplicated into independent copies" of the List (both threads point to the same object), and a separate process cannot receive an "original reference" since JVM memory addresses are meaningless across process boundaries. C is wrong because threads never share stack-local variables with each other — stacks are strictly private — and a separate process does not gain access to in-process heap objects after a message is delivered.
A reliable memory trick: stack = private, heap = shared (within JVM), process boundary = copy. Keep these three rules in mind whenever a question mixes threads and inter-process communication.
- Which assessment best captures the threads-versus-processes tradeoff?
Answer: Threads favor direct cache sharing, while processes favor independent lifecycle and isolation; the requirements therefore involve a genuine tradeoff.
When evaluating concurrency and process design, always ask two separate questions: how is data shared? and what happens when one component fails or restarts? These two concerns pull in opposite directions, and recognizing that tension is exactly what this question tests.
In Java, threads share the same JVM heap by definition, meaning two modules running as threads can pass large cache objects via direct reference — no serialization, no copying. That's a massive performance win. However, because they share the same JVM process, a crash or restart of one module necessarily affects the other. Processes, by contrast, run in separate JVMs with isolated heaps, enabling truly independent lifecycle management — you can restart one without touching the other. The tradeoff: sharing now requires inter-process communication (IPC), serialization, or shared memory mechanisms, which add overhead. The scenario describes both requirements simultaneously, so neither model wins cleanly. That makes D correct — it honestly names what each model favors and acknowledges the genuine tradeoff.
A is wrong because threads do not own separate heaps; all threads inside one JVM share a single heap, and a JVM crash takes every thread down together — there is no failure isolation.
B inverts reality. Processes enable independent deployment, not threads. And processes do not support direct reference sharing — heaps are separate by design.
C is a fabrication. JVM heaps are never shared between processes just because modules use identical classes. Class identity does not bridge process boundaries.
Your strategy: when a question lists two competing requirements, be suspicious of any answer claiming one technology satisfies both without compromise — real engineering almost always involves tradeoffs.
- Which statement best compares the visibility of updates in the two versions?
Answer: Only Version 1 can share that static field directly; Version 2 has separate JVM memory and requires an interprocess mechanism.
When you see a question about static fields and JVM processes, anchor yourself in one core principle: a JVM instance owns its own memory space, and static fields live within that memory.
In Version 1, two threads run inside the same JVM. Threads share the same heap, which means they share the same class definition and its static fields. When one thread updates Counter's static field, that change is visible to the other thread (subject to proper synchronization). This is exactly why volatile and synchronized matter — threads can interfere with each other precisely because they share static state. Version 1 demonstrates true direct sharing.
In Version 2, you launch two separate JVM processes. Each process loads its own copy of Counter, complete with its own independent static field. A change in Process 1's field has zero effect on Process 2's field. To communicate between them, you'd need an external mechanism — sockets, files, a database, shared memory via OS-level tools, etc.
B is correct because it accurately captures this distinction. A is wrong because static fields are not magically shared across JVMs on the same machine — "same machine" is irrelevant to JVM memory isolation. C has it completely backwards: threads do not receive independent copies of static state; processes do. D is wrong because it incorrectly claims threads have separate heaps — they don't. Threads within one JVM share a single heap; only processes are fully isolated.
Study tip: Remember the hierarchy — threads share heap within a JVM; processes are completely isolated. Any cross-process communication requires explicit interprocess mechanisms.
- Which conclusion is most accurate?
Answer: Up to four worker calculations may execute in parallel, subject to JVM and operating-system scheduling.
When you see a question about Java threads and parallelism, focus on two things: how many threads exist, and how many cores are available — because the lesser of the two limits actual parallel execution.
Java threads are mapped to native OS threads, which the operating system schedules onto physical processor cores. This means threads in a single JVM can achieve true hardware parallelism — they aren't restricted to taking turns on one core. In this scenario, four worker threads exist and eight cores are available. Since each worker is CPU-bound and runnable, the JVM and OS can schedule all four threads simultaneously, one per core. That makes C the correct conclusion: up to four calculations may run in parallel, with the exact behavior subject to JVM and OS scheduling decisions.
Answer A is wrong because it describes a single-threaded execution model. Java threads are not confined to one core — that misconception confuses Java with older cooperative threading models or the Python GIL, neither of which applies here. Answer B is wrong for the opposite reason: the JVM doesn't automatically spawn worker threads to fill every available core. You created four threads; those four are what exist. The JVM won't magically conjure four more to use the remaining cores. Answer D is wrong because it falsely claims threads can never achieve hardware parallelism. Threads absolutely can run in parallel across cores within a single JVM process — that's a core feature of the Java threading model.
A useful rule of thumb: parallel thread count ≤ min(threads created, available cores). On exam questions, watch for answers that either over-restrict (one core only) or over-promise (automatic scaling to all cores) — both are traps.
- Why can the revised design still allow conflicting file updates?
Answer: A Java monitor coordinates threads using the same lock object in one JVM, not separate lock objects in different processes.
When you see a question about Java synchronization and multiple JVMs, the core concept to focus on is the scope of a Java monitor. A synchronized block in Java uses a monitor tied to a specific object instance within a single JVM's memory space. Monitors are not shared across process boundaries — they only coordinate threads that literally share the same heap object.
This is exactly why A is correct. When both workers lived in one JVM, they synchronized on the same lock object, so Java's monitor mechanism could enforce mutual exclusion. Once each worker moves to its own JVM, each has its own independent lock object in its own memory space. Even if both objects are "equivalent" in code, they are completely unrelated at runtime. Neither JVM's monitor knows about the other's, so both threads can enter their respective synchronized blocks simultaneously — and both can write to the file at the same time.
B is wrong because Java monitors have nothing to do with process creation — they govern thread access to shared resources. C is wrong because JVMs do not communicate with each other to disable synchronized blocks; that's not a feature that exists anywhere in the Java specification. D is wrong because there is no global monitor namespace shared across JVMs — monitors are strictly local to the JVM instance that created the lock object. Daemon thread status is also irrelevant to monitor behavior.
The key study tip: whenever a question involves concurrency across separate JVMs or processes, remember that Java's synchronized keyword only protects against intra-process race conditions. Cross-process coordination requires external mechanisms like file locks (FileChannel.lock()) or a shared distributed lock.
- Assuming isolation is not required, which comparison is generally correct?
Answer: Design X can pass ordinary object references, while Design Y generally needs serialization, messaging, or another interprocess mechanism.
When comparing single-JVM threading versus multi-JVM processes, the central concept is memory sharing. Ask yourself: do these execution units share the same heap, or do they live in completely separate memory spaces?
Within a single JVM, all threads share the same heap. This means two threads can pass a reference to a mutable object — a simple pointer — and both can read or write that object directly. No copying, no serialization, no network hop. This is exactly what Design X does, making it highly efficient for exchanging thousands of small objects per second.
Design Y, however, runs each component in its own JVM process. Each JVM maintains its own isolated heap, so a memory address in one process is meaningless in another. To exchange data, you must externalize it — through serialization, sockets, shared databases, message queues, or similar interprocess communication (IPC) mechanisms. This overhead is why Design X is the better fit when isolation is not required. That reasoning confirms A is correct.
B is backwards — it's Design X (same JVM, shared heap) that can pass raw references, not Design Y. Thread stacks are separate, but the heap is shared, so serialization between threads is unnecessary. C is wrong because sharing class definitions doesn't matter when processes have separate heaps; you still can't dereference another process's memory pointer. D incorrectly applies the multi-process rule to threads — threads within one JVM do share a single heap.
As a study tip: always distinguish threads (shared heap, separate stacks) from processes (separate heaps entirely). This distinction drives many concurrency and architecture questions in Java exams.
- Which design best supports the team's isolation goal?
Answer: Run each extension in its own process, accepting interprocess communication and higher resource overhead for stronger isolation.
When designing a system that runs untrusted or potentially buggy third-party code, the core question is: how do you contain a failure so it can't damage the rest of the system? This question tests your understanding of process isolation versus thread isolation in Java.
Processes are the strongest isolation boundary the operating system provides. Each process gets its own memory space, its own heap, and its own lifecycle. If an extension running in a separate process enters an infinite loop or crashes, you can kill that process without touching the main server or any other extension. That's exactly what answer A describes — and it's the correct choice. Yes, interprocess communication (IPC) adds overhead, but the question explicitly asks about the team's isolation goal, and processes deliver the most robust form of it.
Answer B is wrong because daemon thread status has nothing to do with memory consumption. A daemon thread simply means the JVM won't wait for it to finish before exiting — it does not restrict heap usage or prevent an infinite loop from stealing CPU cycles.
Answer C is wrong because synchronization (synchronized) is a concurrency control mechanism for managing shared resource access — it does not isolate failures, and threads absolutely do not get separate heaps. All threads in a JVM share the same heap.
Answer D is wrong because threads in a pool share the same JVM heap and state. You cannot reliably "forcibly terminate" a runaway thread in Java — Thread.stop() is deprecated precisely because it leaves shared state corrupted.
Study tip: Remember the hierarchy — threads share memory within a process, but processes are isolated from each other by the OS. When a question asks about fault isolation, think processes first.
- What is the best evaluation of the prediction?
Answer: It is generally incorrect because JVM processes usually require separate runtime resources, heaps, and process startup.
When comparing threads versus processes in Java, the key question is: what resources does each require at startup, and what does each share? Threads within a single JVM share the same heap, class-loader, and runtime environment. Processes, by contrast, each spin up their own JVM instance — meaning a separate heap, separate class metadata, separate native memory, and full OS-level process initialization overhead.
That's exactly why B is correct. Replacing 100 short-lived threads with 100 short-lived JVM processes almost certainly increases both startup time and memory consumption, not decreases them. Each new process must load the JVM, initialize the runtime, allocate a fresh heap, and register with the OS scheduler. Threads skip all of that because they piggyback on an already-running JVM.
A gets the causality backwards — yes, each process starts a private JVM, but that's precisely why process startup costs are higher, not lower. The developer's prediction would be hurt by this fact, not supported.
C is factually wrong. Operating systems use virtual memory and can allocate memory to processes that aren't currently executing (e.g., pages can be swapped out). This has no bearing on whether processes use less memory than threads anyway.
D is a made-up rule. There is no universal constant like "exactly twice as much" memory for processes versus threads — resource consumption varies widely based on heap settings, OS, and workload. "Always" and "exactly" are red flags for extreme answer choices.
A good study tip: whenever you see words like "always," "necessarily," or "exactly" in answer choices, be skeptical — Java memory and performance behavior is rarely that absolute.
- Which outcome is the most reasonable expectation of that change?
Answer: Each JVM has separate heap and garbage-collection activity, though both processes still compete for machine resources.
When you see a question about JVM processes and garbage collection, think about what isolation a separate process actually provides — and what it doesn't.
Each JVM process manages its own independent heap. That means garbage collection in one JVM has no direct impact on the other — a stop-the-world pause in Process A won't freeze threads running in Process B. This is the core benefit of splitting subsystems across processes, and it's exactly what C describes: separate heaps with independent GC activity. The trade-off, however, is that both processes still run on the same physical machine, so they compete for CPU cycles, RAM, disk I/O, and network bandwidth. Isolation is logical, not physical.
A is wrong because it conflates process memory management with garbage collection. The JVM still allocates objects on its heap and still runs GC during the process's lifetime — process exit has nothing to do with when GC occurs.
B describes something that simply doesn't exist. Two separate JVM processes never share a heap. Heap memory is private to each process by design; the operating system doesn't coordinate GC between them.
D is the most tempting distractor because it sounds like the "ideal" answer. But processes absolutely do compete for CPU time, memory bandwidth, and I/O. Moving to a second JVM reduces GC interference; it doesn't create a physics-defying guarantee of zero latency interaction.
As a study tip: distinguish between logical isolation (separate heap, separate GC) and physical isolation (dedicated hardware). Java exam questions often test whether you conflate the two.
- Which statement best describes these failures?
Answer: The thread exception normally terminates that thread, while the worker process exit normally leaves the separate server process running.
When you see a question mixing threads and processes, the key concept to anchor on is isolation: threads share a process, while separate JVM processes are fully independent OS-level entities.
A thread is a lightweight execution unit within a JVM process. When a thread throws an uncaught RuntimeException, the JVM's default uncaught exception handler terminates that thread only — the server process, its other threads, and its memory all remain intact. A child JVM process, by contrast, is a completely separate OS process. When it exits (even with a nonzero status indicating failure), the parent server process is unaffected unless it explicitly checks the exit code. This is exactly what B describes, making it the correct answer.
A is wrong because it contradicts the fundamental distinction between threads and processes. Threads and separate JVM processes do not share one OS process — that's the whole point of ProcessBuilder or Runtime.exec(). Multiple JVMs on the same machine are independent OS processes.
C gets things backwards twice. An uncaught exception does terminate its thread (the thread's stack unwinds and the thread dies), and a child process exit has no mechanism to "restart" the server's main thread — processes don't reach into each other's thread schedulers.
D is wrong because neither failure is silently ignored by default. An uncaught thread exception triggers the UncaughtExceptionHandler (printing a stack trace by default), and the server can observe the child process exit code via Process.exitValue() or waitFor().
A useful pattern: whenever a question contrasts threads vs. processes, ask yourself what is the unit of isolation? Threads share; processes are separate. That single principle resolves most such questions.