A team ships a lazy singleton using double-checked locking, but the `instance` field is a plain (non-volatile) `Object`. Under load on a multi-core JVM, another thread occasionally sees a non-null `instance` whose fields are still at their default values. What is the precise root cause?
- A. The compiler removes the inner null check via lock elision, so two threads run the constructor concurrently
- B. Without volatile, the write publishing the reference can be reordered before the constructor's field writes complete, so a reader sees a non-null but partially-constructed object ✓
- C. The synchronized block only guarantees mutual exclusion, so the second thread always re-runs the constructor and overwrites the first instance
- D. HotSpot never caches object references in registers, so the issue is purely a heap-visibility flush that a memory barrier on read would fix
Correct answer: B. Without volatile there is no happens-before edge, so the reference publication can be reordered ahead of the constructor's writes, exposing a partially-constructed object to another thread.
Consider `private volatile int[] data = new int[10];` accessed by many threads that do `data[i]++` concurrently on distinct-looking but sometimes overlapping indices. Why does marking the array reference `volatile` fail to make these updates thread-safe?
- A. volatile only establishes visibility/ordering for reads and writes of the reference itself, not for reads/writes of the array's elements, which remain unsynchronized ✓
- B. volatile arrays are copied on every write, so the increment operates on a stale snapshot
- C. volatile forces every element access through a lock, but the lock is reentrant so nested increments corrupt the counter
- D. The JIT strips volatile from array fields during escape analysis, silently downgrading it to a plain field
Correct answer: A. The volatile modifier applies to the reference variable, not the elements; per-element mutations have no memory-model guarantees and the `++` is also non-atomic.
Two threads run this code with shared `int x = 0; boolean ready = false;` — Thread A: `x = 42; ready = true;` — Thread B: `if (ready) System.out.println(x);`. Neither variable is volatile or synchronized. Which statement about permitted outcomes is correct under the JMM?
- A. B can only ever print 42, because assignment order in A is preserved by program order across threads
- B. B can print 0 or observe ready==true before x==42, because without a happens-before relation A's writes may be observed out of order ✓
- C. The program is guaranteed to deadlock since ready is read without a lock
- D. B will always block until ready becomes true because reads of shared booleans are implicitly synchronized
Correct answer: B. Absent a happens-before edge, Thread B may observe `ready==true` while still reading the stale `x==0` due to permitted reordering/visibility gaps.
You have a producer-consumer using `wait()`/`notify()`. A reviewer insists the consumer's `wait()` must sit inside `while (queue.isEmpty())` rather than `if (queue.isEmpty())`. What is the strongest technical justification?
- A. `if` would hold the monitor during wait, whereas `while` releases it, preventing a deadlock
- B. A thread returning from wait may find the condition false again due to spurious wakeups or another consumer having drained the item, so the predicate must be re-checked in a loop ✓
- C. `notify()` only wakes threads that used `while`, so `if`-based waiters are never scheduled
- D. `while` guarantees FIFO fairness among waiters, which `if` cannot provide
Correct answer: B. wait() can return without the intended condition holding (spurious wakeups, or another thread consumed the item), so the guard must be re-tested in a loop.
A `@Service` bean has a public `outer()` method (no annotation) that calls `this.inner()`, where `inner()` is annotated `@Transactional(propagation = REQUIRES_NEW)`. At runtime `inner()` runs in no transaction at all. Why?
- A. REQUIRES_NEW is ignored unless the outer method is also @Transactional, so propagation silently downgrades to SUPPORTS
- B. The self-invocation `this.inner()` bypasses the Spring CGLIB/JDK proxy, so the transactional advice around inner() never fires ✓
- C. REQUIRES_NEW requires an XA datasource; without one Spring skips transaction creation and logs a warning
- D. Spring caches the transaction status per thread, and since outer() opened none, inner() inherits the empty context permanently
Correct answer: B. Transactional advice lives on the proxy; an internal `this.` call goes straight to the target instance, skipping the proxy and thus all propagation handling.
A production service running Hibernate returns a `User` entity from a `@Transactional` service method to a controller, which then accesses `user.getOrders()` (a `LAZY` collection) to render JSON. Users get intermittent `LazyInitializationException`. What is the correct root-cause explanation?
- A. The collection was mapped EAGER, so Hibernate throws when it detects a redundant fetch in the view layer
- B. The persistence context/session closed when the transactional method returned, so the proxy has no session to initialize the collection during controller-layer access ✓
- C. The exception occurs because getOrders() triggers an N+1 query that exceeds the connection pool, timing out the fetch
- D. Jackson serializes the collection on a different thread that lacks the ThreadLocal session, unlike single-threaded access which succeeds
Correct answer: B. Lazy collections need an open session to initialize; once the transactional boundary closes the session, touching the uninitialized proxy later throws LazyInitializationException.
A REST endpoint calls a downstream payment API. On timeout your client retries. Occasionally a customer is charged twice. Which approach most directly prevents duplicate side effects while keeping at-least-once retry semantics?
- A. Switch retries to at-most-once by disabling them entirely, accepting occasional lost charges
- B. Attach a client-generated idempotency key to each logical request so the server deduplicates retries of the same operation ✓
- C. Wrap the call in a distributed lock so only one node can call the payment API at a time
- D. Increase the client socket timeout so responses always arrive before a retry is triggered
Correct answer: B. An idempotency key lets the server recognize a retried request as the same logical operation and return the original result instead of charging again.
You must reliably publish an event to Kafka whenever a row is written to your SQL database, but a crash between the DB commit and the Kafka send can lose events (dual-write problem). Which pattern correctly guarantees the event is not lost?
- A. Send to Kafka first, then commit the DB row, so the broker is the source of truth
- B. Use the Outbox pattern: write the event into an outbox table in the same DB transaction, then a separate relay reads and publishes it, retrying until acknowledged ✓
- C. Wrap both the DB commit and the Kafka producer.send() in a single synchronized block
- D. Enable Kafka idempotent producer, which retroactively rolls back the DB row if the send fails
Correct answer: B. The Outbox pattern makes the event write atomic with the business data (one DB transaction), and a separate relay guarantees at-least-once delivery to Kafka.
A latency-sensitive service (P99 pause budget ~10ms) runs on a 64GB heap and suffers multi-hundred-millisecond stop-the-world pauses during full GCs with the Parallel collector. Which change best fits the requirement, and why?
- A. Switch to ZGC, because it performs concurrent marking and relocation to keep pauses sub-millisecond largely independent of heap size ✓
- B. Switch to the Serial collector to reduce GC thread contention on the large heap
- C. Keep Parallel GC but set -XX:MaxGCPauseMillis=10, which converts full GCs into concurrent cycles
- D. Shrink the heap to 4GB so full GCs complete within the 10ms budget
Correct answer: A. ZGC is designed for low, near-constant pause times that scale to large heaps by doing marking and relocation concurrently, matching a tight P99 pause goal.
A mutable object is used as a key in a `HashMap`. After insertion, code mutates a field that participates in `equals`/`hashCode`. Later `map.get(sameKeyReference)` returns null even though the entry is clearly present. What is the precise mechanism?
- A. HashMap rehashes on every mutation, so the entry was moved to a bucket the key no longer maps to
- B. The entry was stored in the bucket derived from the original hashCode; the mutated key now hashes to a different bucket, so the lookup probes the wrong bucket and misses the entry ✓
- C. equals() now returns false against itself, so identity comparison inside get() fails
- D. Treeification converted the bucket to a red-black tree keyed by the old hash, corrupting the lookup index
Correct answer: B. The entry stays in the bucket chosen at insertion time; a mutated hashCode routes get() to a different bucket, so it never finds the entry.
What does the volatile keyword guarantee?
- A. Atomicity of compound operations like i++
- B. Visibility of writes to all threads ✓
- C. Mutual exclusion around the field
- D. Reordering only within one thread
Correct answer: B. volatile ensures visibility and ordering of reads/writes but not atomicity of compound operations.
Under the standard parent-delegation model, a ClassLoader first attempts to load a class from?
- A. The current classloader itself
- B. Its parent classloader ✓
- C. The bootstrap loader by scanning disk
- D. The system classpath directly
Correct answer: B. Delegation asks the parent first, and only loads locally if the parent cannot.
How is the heap organized in the G1 garbage collector?
- A. Contiguous young and old spaces
- B. Equal-sized regions ✓
- C. Purely by object age generations
- D. Thread-local allocation buffers only
Correct answer: B. G1 partitions the heap into many equal-sized regions dynamically assigned roles.
What does String.intern() return?
- A. A freshly allocated String copy
- B. The canonical reference from the string pool ✓
- C. The string's hash code
- D. An interned char array
Correct answer: B. intern() returns the canonical pooled reference, adding the string if absent.
How does Java 8's ConcurrentHashMap achieve thread safety on writes?
- A. A single global lock
- B. Segment locks as in Java 7
- C. CAS on empty bins plus synchronized on the bin head ✓
- D. Copy-on-write of the whole table
Correct answer: C. Java 8 uses CAS for empty bins and synchronizes on the first node of a non-empty bin.
For a correct double-checked-locking singleton, the instance field must be declared?
- A. static only
- B. final
- C. volatile ✓
- D. transient
Correct answer: C. volatile prevents a thread from seeing a partially constructed instance due to reordering.
Which statement about Object.finalize() is correct?
- A. It runs immediately when the object becomes unreachable
- B. It is guaranteed to run before JVM exit
- C. It may never be called at all ✓
- D. It always runs on the main thread
Correct answer: C. The JVM makes no guarantee that finalize() is ever invoked.
Integer.valueOf caches boxed instances for which value range?
- A. 0 to 255
- B. -128 to 127 ✓
- C. -256 to 255
- D. No values are cached
Correct answer: B. The Integer cache covers -128 to 127 by default, so == can be true in that range.
What triggers a ConcurrentModificationException from an ArrayList iterator?
- A. A concurrent read on another thread
- B. A modCount mismatch detected during iteration ✓
- C. The presence of null elements
- D. An internal capacity resize
Correct answer: B. The fail-fast iterator compares an expected modCount against the list's modCount and throws on mismatch.
Which action establishes a happens-before relationship in the Java Memory Model?
- A. Two unsynchronized reads on different threads
- B. Unlocking a monitor before a later lock of the same monitor ✓
- C. Setting a higher thread priority
- D. Calling System.gc()
Correct answer: B. An unlock happens-before any subsequent lock of the same monitor.
What does the happens-before relationship in the Java Memory Model establish?
- A. Visibility and ordering guarantees between actions ✓
- B. Thread priority ordering
- C. Garbage collection ordering
- D. Method invocation ordering
Correct answer: A. happens-before defines when one action's memory effects are guaranteed visible and ordered before another's.
What is a well-known hazard of using a plain HashMap concurrently in pre-Java 8 JVMs?
- A. A guaranteed compile error
- B. An infinite loop during a concurrent resize/rehash ✓
- C. A guaranteed deadlock every time
- D. No issue at all
Correct answer: B. Concurrent resizing could corrupt the linked bucket list into a cycle, causing an infinite loop on get().
In the G1 garbage collector, what is a Region?
- A. A fixed-size subdivision of the heap ✓
- B. A pool of worker threads
- C. A class-loader scope
- D. A single stack frame
Correct answer: A. G1 partitions the heap into equal fixed-size regions that are dynamically assigned as Eden, Survivor, or Old.
What does Collections.unmodifiableList() return?
- A. A read-only view that throws on mutation attempts ✓
- B. A deep copy of the list
- C. A synchronized list
- D. A thread-safe concurrent list
Correct answer: A. It returns a wrapper view backed by the original list; mutation throws UnsupportedOperationException but backing changes still show through.
How do return statements in try and finally interact?
- A. The try block's return always wins
- B. A return in finally overrides the try block's return ✓
- C. finally never runs after a return
- D. It is a compile error
Correct answer: B. A return in finally executes last and suppresses/overrides any return value from the try block.
What does declaring an instance method synchronized do?
- A. Locks on the instance (this) monitor ✓
- B. Locks on the Class object
- C. Acquires a single global JVM lock
- D. Performs no locking
Correct answer: A. A synchronized instance method acquires the intrinsic lock of the object (this).
Which delegation model does the standard Java ClassLoader hierarchy follow?
- A. Parent-first delegation ✓
- B. Child-first delegation
- C. No delegation
- D. Random delegation
Correct answer: A. By default a class loader delegates to its parent first before attempting to load a class itself.
What happens if you invoke start() twice on the same Thread object?
- A. It runs the thread body twice
- B. It throws IllegalThreadStateException ✓
- C. It silently does nothing
- D. It spawns a brand-new thread
Correct answer: B. A Thread can be started only once; a second start() throws IllegalThreadStateException.
What is type erasure in Java generics?
- A. Generic type information is removed at compile time ✓
- B. Generics are enforced at runtime
- C. Types are erased during class loading
- D. Primitives are automatically boxed
Correct answer: A. The compiler erases generic type parameters to their bounds, so the type info is not retained at runtime.
How do CompletableFuture.thenApply and thenApplyAsync differ?
- A. Both always run asynchronously
- B. thenApply may run in the completing thread; thenApplyAsync uses an executor ✓
- C. Both always run on the main thread
- D. Both always run in the same fixed thread
Correct answer: B. thenApply may execute in the thread that completed the stage, while thenApplyAsync submits the work to an executor.