Skip to content
Laviyx Learn

Try

Java course menu

Advanced Java Interview Questions and Answers

Advanced Java interview questions with answers: JVM memory areas, garbage collection, the Java Memory Model and volatile, synchronized vs locks vs atomics, ConcurrentHashMap, ExecutorService, virtual threads, generics and type erasure, streams laziness, String pool, and class loading.

Advanced6 min readUpdated
On this page

Senior and backend interviews dig into the JVM, memory, concurrency and the finer points of the type system. Precise vocabulary matters, and so does knowing the trade-offs.

The JVM and memory#

1. What are the main JVM memory areas?#

Show solution
  • Heap: all objects and arrays; shared by all threads; managed by the garbage collector. Usually split into generations (young and old).
  • Stack (one per thread): a frame for each method call, holding local variables, parameters and partial results. A StackOverflowError occurs when it runs out, typically through deep recursion.
  • Metaspace: class metadata (since Java 8; it replaced PermGen), allocated in native memory.
  • Program counter and native method stacks: per-thread execution bookkeeping.

Primitive locals live in stack frames; objects always live on the heap, and stack frames only hold references to them (the JIT may optimize some allocations away through escape analysis).

2. How does garbage collection work?#

Show solution

The GC frees objects that are no longer reachable from GC roots (local variables in active frames, static fields, active threads). Most collectors are generational: new objects are allocated in the young generation, which is collected frequently and cheaply because most objects die young; survivors are promoted to the old generation, which is collected less often. Modern collectors include G1 (the default), ZGC and Shenandoah, which keep pauses very short even for large heaps. You cannot force collection (System.gc() is only a hint); you help the GC by not keeping unnecessary references, for example in static caches or listeners.

3. Can Java have memory leaks?#

Show solution

Yes: not of unreachable memory, but of objects that are still reachable and never used again. Common causes: ever-growing static collections or caches, listeners that are never removed, ThreadLocal values in thread pools, and unclosed resources. Tools such as heap dumps, VisualVM and Java Flight Recorder help find them.

4. What is the String pool?#

Show solution

The JVM keeps a pool of string literals, so identical literals share one String object. Strings created at run time are not pooled unless you call intern(). This is why "a" == "a" is true while new String("a") == "a" is false, and why strings must be compared with equals.

Concurrency#

5. What does volatile do?#

Show solution

volatile guarantees visibility and ordering: a write to a volatile field by one thread is visible to subsequent reads by other threads (it creates a happens-before relationship), and it prevents certain reorderings. It does not make compound actions like count++ atomic. Typical use: a volatile boolean running flag that one thread sets to stop another.

6. synchronized vs ReentrantLock vs atomic classes?#

Show solution
  • synchronized: simple, block-structured mutual exclusion plus visibility; locks are released automatically.
  • ReentrantLock: the same semantics with extras such as tryLock with a timeout, interruptible locking, fairness and multiple Conditions; it must be unlocked in a finally block.
  • AtomicInteger / AtomicLong / LongAdder: lock-free updates of single variables using compare-and-swap; the fastest choice for counters.

Use the simplest tool that protects your invariant; if the invariant spans several variables, you need a lock.

7. How does ConcurrentHashMap achieve thread safety?#

Show solution

It allows concurrent reads without locking, and concurrent writes to different parts of the table: modern implementations use compare-and-swap for empty buckets and lock only the individual bucket (its first node) being updated. Atomic compound operations such as merge, compute and putIfAbsent make "check then act" safe. It does not allow null keys or values (so get returning null always means "absent"), and its iterators are weakly consistent rather than fail-fast.

8. What are virtual threads, and when do they help?#

Show solution

Virtual threads (Java 21) are lightweight threads scheduled by the JVM onto a small pool of carrier (platform) threads. When a virtual thread blocks on I/O, it is unmounted and its carrier runs other work, so millions of virtual threads are practical. They make the simple thread-per-request style scale for I/O-bound work. They do not speed up CPU-bound work, and code that blocks while holding a synchronized lock could pin the carrier thread in Java 21 (later releases reduce this).

9. What is a deadlock and how do you avoid it?#

Show solution

Two (or more) threads each hold a lock the other needs, so all wait forever. Avoid it by always acquiring locks in a consistent global order, keeping critical sections short, using tryLock with timeouts, and preferring higher-level concurrency utilities over hand-written locking.

Language and libraries#

10. What is type erasure, and what are its consequences?#

Show solution

Generic type information is checked at compile time and then erased: at run time, List<String> and List<Integer> are both List. Consequences: no primitive type arguments (List<int>), no new T() or new T[], no instanceof List<String>, and two overloads differing only by generic type (m(List<String>) and m(List<Integer>)) clash. Erasure kept generics backward compatible with pre-Java 5 code.

11. Are streams lazy? What does that mean?#

Show solution

Yes. Intermediate operations (filter, map, sorted) only build a pipeline; nothing runs until a terminal operation (collect, count, forEach). Elements then flow through the pipeline one at a time, which allows short-circuiting:

Java
import java.util.stream.Stream;

public class Main {
    public static void main(String[] args) {
        int first = Stream.of(5, 12, 7, 20, 3)
                .peek(n -> System.out.println("checking " + n))
                .filter(n -> n > 10)
                .findFirst()
                .orElse(-1);
        System.out.println("result " + first);
    }
}
Output
checking 5
checking 12
result 12

Only two elements were examined, because findFirst stopped the pipeline as soon as it had a result.

12. What is the difference between fail-fast and fail-safe iterators?#

Show solution

Fail-fast iterators (ArrayList, HashMap) detect structural modification during iteration and throw ConcurrentModificationException. Fail-safe or weakly consistent iterators (CopyOnWriteArrayList, ConcurrentHashMap) iterate over a snapshot or tolerate concurrent changes without throwing, possibly not reflecting the latest updates.

13. How does class loading work?#

Show solution

Classes are loaded lazily, the first time they are used, by a hierarchy of class loaders (bootstrap, platform and application) using parent delegation: a loader first asks its parent, so core classes like java.lang.String always come from the bootstrap loader. Loading is followed by linking (verification, preparation, resolution) and initialization, when static initializers run. This is why a static block runs only once, on first use of the class.

14. What are sealed classes, and why combine them with records and switch?#

Show solution

A sealed class or interface lists exactly which classes may extend or implement it (permits). Combined with records and pattern-matching switch, the compiler knows every possible subtype, so switches can be exhaustive without a default, and adding a new subtype causes compile errors wherever it is not handled. This models closed sets of alternatives ("algebraic data types") safely.

Next steps#

Practise turning these ideas into code in Coding Challenges.

Finished this lesson?