Java Advanced Topics Flashcards

Streams, Concurrency, Memory, Collections (35 cards)

1
Q

What are intermediate and terminal operators in the Java Stream API?

A

Intermediate operators:
* Return a new stream; can be chained.
* Do not trigger processing.
* Examples: filter, map, flatMap, sorted, distinct.

Terminal operators:
* Produce a result or side effect; trigger stream processing.
* Examples: collect, forEach, reduce, count, anyMatch.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Can you mention some terminal operators that end stream processing without going through all elements?

A

Short-circuiting terminal operators:
* May finish processing before all elements are examined.

Examples:
* anyMatch()
* allMatch()
* noneMatch()
* findFirst()
* findAny()

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

How do parallel streams work, and what are their advantages and pitfalls?

A

How they work:
* Split data into multiple parts and process them concurrently using multiple threads (ForkJoinPool).
* Use .parallelStream() or .parallel() on a stream.

Advantages:
* Can improve performance for large, CPU-intensive tasks.
* Simplifies parallel processing code.

Pitfalls:
* Overhead may outweigh benefits for small datasets.
* Not always thread-safe if operations have side effects.
* Order may not be preserved (unless using ordered streams).
* Shared mutable state can cause bugs.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

How do you handle exceptions during Java Stream processing?

A

Checked exceptions:
* Streams don’t handle checked exceptions directly; wrap code in try-catch blocks inside lambdas or use custom wrapper methods.

Unchecked exceptions:
* Can be caught outside the stream or inside lambdas.

Common approaches:
* Use try-catch inside the lambda:

list.stream().map(item -> {
    try { return riskyMethod(item); }
    catch (Exception e) { /* handle or rethrow */ }
})
  • Use helper methods or custom functional interfaces to handle checked exceptions.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

How can you debug streams?

A
  • Use peek():
    Insert peek() between stream operations to log or inspect elements.
    Example:
stream.filter(x -> x > 0)
      .peek(System.out::println)
      .map(x -> x * 2)
  • Add logging or breakpoints:
    Place logging statements or breakpoints inside lambdas.
  • Test with small datasets:
    Easier to trace and understand stream behavior.
    Check for side effects:
    Ensure operations are stateless and side-effect free for reliable debugging.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

What is the Executors framework?

A
  • A high-level API for managing and controlling thread execution.
  • Provides factory methods to create thread pools (ExecutorService), scheduled tasks, and single-threaded executors.
  • Simplifies concurrent programming by handling thread creation, reuse, and shutdown.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

How is LinkedHashMap implemented?

A
  • Extends HashMap and maintains a doubly-linked list of entries.
  • Preserves insertion order (or access order if configured).
  • Each entry has pointers to previous and next entries, enabling ordered iteration.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

What is the Java Memory Model? How does it work?

A

Java Memory Model (JMM):
* Defines how threads interact through memory and what behaviors are allowed in concurrent code.
* Specifies rules for visibility, ordering, and atomicity of variable reads/writes.
* Ensures that changes made by one thread to shared variables are visible to others (with proper synchronization).
* Guarantees provided by volatile, synchronized, and final fields.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

How would you identify and troubleshoot a memory leak?

A

Identification:
* Monitor memory usage (e.g., with VisualVM, JConsole, or profilers).
* Look for increasing heap usage and frequent garbage collection.
* Analyze heap dumps for unreachable but referenced objects.

Troubleshooting:
* Check for static collections or caches holding references.
* Review code for listeners, threads, or resources not released.
* Use profiling tools to find reference chains and root causes.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

What are the different phases of garbage collection?

A

Mark: Identify all reachable (live) objects.

Sweep: Remove unreferenced (dead) objects from memory.

Compact (optional): Rearrange remaining objects to eliminate fragmentation.

Copy (in some collectors): Move live objects to a new memory area, leaving dead objects behind.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

What is garbage collection?

A
  • Automatic process that frees memory by removing objects no longer referenced by the program.
  • Helps prevent memory leaks and reduces manual memory management.
  • Managed by the Java Virtual Machine (JVM).
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

What is throughput and latency in terms of garbage collection?

A

Throughput:
* The percentage of total time the application spends doing useful work (not garbage collection).
* Higher throughput means less time spent in GC.

Latency:
* The pause time experienced by the application during garbage collection.
* Lower latency means shorter or less frequent GC pauses.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

What is the subtype of Set that supports sorted order?

A
  • SortedSet is the subtype of Set that maintains elements in a sorted order.
  • TreeSet is the main implementation of SortedSet.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

Can we have a default method in a functional interface?

A
  • Yes, a functional interface can have default and static methods.
  • It must have only one abstract method (the functional method).
  • Default methods do not count toward the single abstract method requirement.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

How would you decide which GC algorithm to use in certain situations?

A

Throughput-focused applications:
Use collectors like Parallel GC (default in many JVMs); best for batch processing or server-side apps where pause times are less critical.

Low-latency applications:
Use G1 GC or ZGC/Shenandoah GC; suitable for real-time systems or user-facing apps where short pause times are important.

Small applications or limited resources:
Serial GC is simple and has low overhead; good for single-threaded or small footprint apps.

Large heaps or high scalability:
G1 GC, ZGC, or Shenandoah GC handle large memory sizes and minimize pause times.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

What problems could arise if a mutable object is used as a key in a HashMap?

A

If the key’s fields (used in hashCode() or equals()) change after insertion, the map may not find the key.

Retrieval, update, or removal operations can fail or behave unpredictably.

Can lead to memory leaks (unreachable entries remain in the map).

17
Q

What are virtual threads?

A

Lightweight threads introduced in Java (Project Loom) to simplify concurrent programming.

Managed by the JVM, allowing thousands of threads with minimal resource usage.

Each virtual thread is scheduled by the JVM, not directly mapped to OS threads.

Makes it easier to write scalable, blocking code without complex thread management.

18
Q

What’s the difference between ExecutorService and ForkJoinPool?

A

ExecutorService:
* General-purpose interface for managing and executing tasks asynchronously.
* Supports fixed, cached, single-threaded, and scheduled thread pools.
* Tasks are independent; no built-in support for task splitting or joining.

ForkJoinPool:
* Specialized implementation of ExecutorService for parallelism.
* Designed for tasks that can be recursively split into subtasks (fork/join framework).
* Efficiently handles divide-and-conquer algorithms.

19
Q

What are atomic variables?

A

Special classes in java.util.concurrent.atomic package.

Provide thread-safe, lock-free operations on single variables (e.g., AtomicInteger, AtomicLong).

Support atomic operations like increment, decrement, compare-and-set.

Useful for counters, flags, and other shared variables in concurrent code.

20
Q

What do wait(), notify(), and notifyAll() do in regards to threads?

A

wait():
Causes the current thread to release the monitor and wait until another thread calls notify() or notifyAll() on the same object.

notify():
Wakes up one waiting thread on the same object’s monitor.

notifyAll():
Wakes up all waiting threads on the same object’s monitor.

All must be called from synchronized context (inside a synchronized block or method).

21
Q

What makes a class or method thread-safe?

A

Thread-safe means the class or method works correctly when accessed by multiple threads at the same time.

Achieved by:
* Synchronizing access to shared data (synchronized keyword, locks).
* Using immutable objects.
* Using thread-safe classes (e.g., ConcurrentHashMap, AtomicInteger).

22
Q

Can you explain how inconsistent state can happen in multithreaded applications?

A

Inconsistent state occurs when multiple threads access and modify shared data without proper synchronization.

This can lead to:
* Partial updates (one thread sees data in the middle of being changed).
* Lost updates (changes from one thread overwrite another’s).
* Unexpected results or program errors.

Example:
If two threads increment the same counter without synchronization, both may read the same value and write back the same result, losing one increment.

23
Q

Can you explain how Java’s memory model works with respect to cache and heap memory, particularly in multithreaded contexts?

A

Heap memory:
Shared area where all objects and class variables are stored.
All threads can access the heap, but changes may not be immediately visible to other threads due to caching.

CPU caches:
Each thread may run on a different CPU core with its own cache.
Threads may see stale values if changes in one cache are not flushed to main memory (heap).

Java Memory Model (JMM):
Defines rules for visibility and ordering of variable reads/writes between threads.
Synchronization (synchronized, volatile, etc.) ensures changes in one thread are visible to others by flushing caches to main memory.

24
Q

What is a race condition? How do you detect it?

A

Race condition:
* Occurs when two or more threads access shared data at the same time, and the result depends on the timing of their execution.
* Can lead to unpredictable or incorrect results.

Detection:
* Look for inconsistent or unexpected behavior in multithreaded code.
* Use code reviews to spot unsynchronized access to shared variables.
* Employ tools like thread analyzers, profilers, or static analysis tools (e.g., FindBugs, VisualVM, Java Flight Recorder).

25
How would you handle deadlock or livelock in your application?
**Deadlock:** Occurs when two or more threads are waiting forever for each other to release resources. Prevention/handling: * Acquire locks in a consistent global order. * Use try-lock with timeouts (ReentrantLock.tryLock()). * Minimize lock scope and avoid nested locks. * Detect with thread dumps or profilers. **Livelock:** Threads keep changing state in response to each other but make no progress. Prevention/handling: * Add random delays or backoff strategies. * Ensure threads eventually break out of retry loops.
26
How does exception handling work in a multithreading environment?
**Uncaught exceptions in threads:** If a thread throws an uncaught exception, it terminates; the exception does not affect other threads. **Handling exceptions:** * Catch exceptions inside the thread’s run() or call() method. * For thread pools (ExecutorService), check for exceptions using Future.get(), which throws ExecutionException if the task failed. * Use Thread.setUncaughtExceptionHandler() to handle uncaught exceptions globally for threads.
27
How does CompletableFuture enable asynchronous programming?
Represents a future result of an asynchronous computation. Allows non-blocking execution: tasks can run in the background and notify when complete. Supports chaining and combining tasks with methods like thenApply, thenCompose, thenCombine. Handles exceptions with methods like exceptionally and handle. Enables building complex async workflows without manual thread management.
28
**Extending Thread class:** ``` class MyThread extends Thread { public void run() { /* code */ } } new MyThread().start(); ``` **Implementing Runnable interface:** ``` class MyRunnable implements Runnable { public void run() { /* code */ } } new Thread(new MyRunnable()).start(); ``` **Using Callable with ExecutorService:** ``` Callable task = () -> 42; ExecutorService executor = Executors.newFixedThreadPool(2); Future future = executor.submit(task); ``` **Using lambda expressions:** `new Thread(() -> { /* code */ }).start();` **Using thread pools (ExecutorService):** ``` ExecutorService pool = Executors.newFixedThreadPool(4); pool.submit(() -> { /* code */ }); ```
29
What are the various approaches to making a collection thread-safe?
Use synchronized collections: * Wrap with Collections.synchronizedList(), synchronizedMap(), etc. Use concurrent collections: * Use classes from java.util.concurrent (e.g., ConcurrentHashMap, CopyOnWriteArrayList). Manual synchronization: * Synchronize access to the collection using synchronized blocks or methods. Immutable collections: * Use unmodifiable or immutable collections to prevent modification.
30
Explain the key implementation differences between standard collections and thread-safe collections.
**Standard collections (e.g., ArrayList, HashMap):** * Not synchronized; multiple threads can cause data corruption. * No built-in locking or concurrency control. **Thread-safe collections:** Synchronized wrappers: * Use internal synchronization (synchronized keyword) to serialize access (e.g., Collections.synchronizedList()). Concurrent collections: * Use advanced concurrency mechanisms (e.g., lock striping, non-blocking algorithms). * Allow better scalability and performance (e.g., ConcurrentHashMap, CopyOnWriteArrayList). * Minimize locking or use lock-free techniques for higher throughput.
31
What is Java volatile and how does it work?
**volatile keyword:** * Marks a variable so that reads/writes are always done directly from main memory, not CPU cache. * Guarantees visibility: changes by one thread are immediately visible to others. * Does not guarantee atomicity for compound actions (like incrementing). *Use for flags or variables shared between threads where atomicity isn’t required.*
32
What is OutOfMemoryError? What are its causes and troubleshooting techniques?
OutOfMemoryError: * Thrown when the JVM cannot allocate more memory for objects. Causes: * Memory leaks (objects not released). * Large data structures or excessive object creation. * Insufficient heap size or memory settings. Troubleshooting: * Analyze heap dumps with tools (e.g., VisualVM, Eclipse MAT). * Monitor memory usage and garbage collection logs. * Check for unclosed resources, static references, or large caches. * Tune JVM memory settings (-Xmx, -Xms).
33
How do you debug a performance issue in a Java application?
**Profile the application:** Use tools like VisualVM, JProfiler, or Java Flight Recorder to identify bottlenecks. **Analyze CPU and memory usage:** Check for high CPU, memory leaks, or excessive garbage collection. **Review thread activity:** Look for thread contention, deadlocks, or blocked threads. **Check database and I/O operations:** Slow queries or file/network access can cause delays. **Optimize code:** Refactor inefficient algorithms, reduce unnecessary object creation, and improve concurrency.
34
Your Java application seems to hang in production. What do you do?
**Collect thread dumps:** Use tools like jstack or VisualVM to capture thread states and identify deadlocks or blocked threads. **Check logs:** Look for errors, exceptions, or long-running operations. **Monitor system resources:** Check CPU, memory, and disk usage for resource exhaustion. **Analyze GC activity:** Excessive garbage collection can cause pauses. **Profile the application:** Use profilers to find bottlenecks or infinite loops.
35
Discuss the difference between JIT (Just-In-Time) and AOT (Ahead-Of-Time) compilation in the JVM.
JIT (Just-In-Time) compilation: * Compiles bytecode to native machine code at runtime, as methods are called. * Optimizes code based on actual usage patterns. * Can adapt and re-optimize code during execution. AOT (Ahead-Of-Time) compilation: * Compiles bytecode to native code before the application runs. * Reduces startup time and can improve predictability. * May not optimize as aggressively as JIT for runtime behavior.