Java Advanced Interview Questions¶
Advanced concepts: patterns, performance, frameworks, concurrency, and enterprise design.
1. What's the difference between volatile, synchronized, and Atomic classes?¶
View Answer
Comparison Table
| Property | volatile | synchronized | Atomic |
|---|---|---|---|
| Purpose | Visibility guarantee | Mutual exclusion (lock) | Atomic operations (lock-free) |
| Lock | None | Monitor lock | Compare-and-swap (CAS) |
| Thread-safe | Read/write visibility only | Full exclusion | Atomic operations only |
| Performance | Fast (no locking) | Slow (locks) | Fast (lock-free, hardware) |
| Use case | Flag variables, stop signals | Shared state, compound operations | Counters, simple updates |
volatile: Visibility Only
volatile boolean shutdown = false;
// Thread 1
while (!shutdown) { // Sees latest value
process();
}
// Thread 2
shutdown = true; // Visible immediately to Thread 1
✅ Fast, but only guarantees visibility.
synchronized: Mutual Exclusion
✅ Full thread-safety, but slower (lock contention).
Atomic: Lock-Free
✅ Fast and atomic, best for simple operations.
2. What's the difference between Runnable and Callable?¶
View Answer
Quick Comparison
| Feature | Runnable | Callable |
|---|---|---|
| Return value | void (no return) | Returns result (<T>) |
| Exception | Cannot throw checked | Can throw checked |
| Method | run() |
call() |
| Executor | execute() |
submit() |
Runnable: No Return
Runnable task = () -> {
System.out.println("Task running");
// No return value
};
executor.execute(task); // Fire-and-forget
Callable: With Return
3. Explain Future vs CompletableFuture¶
View Answer
Future: Blocking
Represents result of async computation, but getting result blocks.
ExecutorService executor = Executors.newFixedThreadPool(1);
Future<String> future = executor.submit(() -> {
Thread.sleep(1000);
return "Result";
});
String result = future.get(); // ❌ Blocks here until ready
Problems: Blocking, limited composition, no callbacks
CompletableFuture: Non-Blocking
Non-blocking chains and callbacks.
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
return "Step 1";
})
.thenApply(s -> s + " → Step 2") // Chain operations
.thenAccept(s -> System.out.println(s)); // Callback (non-blocking)
// Main thread continues, doesn't wait
Comparison Table
| Feature | Future | CompletableFuture |
|---|---|---|
| Blocking | Yes (.get()) | Optional |
| Chaining | Limited | Rich (.thenApply, .thenCombine) |
| Callbacks | No | Yes (.thenAccept, .whenComplete) |
| Error handling | Exception on .get() | .exceptionally, .handle |
| Combining | Manual | Built-in (.thenCombine, .anyOf, .allOf) |
CompletableFuture Methods
- .thenApply(): Transform result
- .thenAccept(): Consume result (no return)
- .thenCombine(): Combine two futures
- .exceptionally(): Handle errors
- .allOf(): Wait for all futures
- .anyOf(): Wait for first future
4. What are design patterns and when to use them?¶
View Answer
Categories of Design Patterns
Creational: Object Creation
- Singleton: One instance per application
- Factory: Create objects without specifying exact classes
- Builder: Construct complex objects step-by-step
Structural: Object Composition
- Decorator: Add behavior to objects dynamically
- Adapter: Make incompatible interfaces compatible
- Proxy: Provide placeholder for another object
Behavioral: Object Collaboration
- Observer: Notify multiple objects of state changes
- Strategy: Encapsulate interchangeable algorithms
- Template Method: Define algorithm skeleton, subclasses fill details
When to Use
| Problem | Pattern | Example |
|---|---|---|
| Need single instance | Singleton | Logger, Database connection |
| Create families of objects | Factory | Database drivers (MySQL, PostgreSQL) |
| Complex object construction | Builder | HTTP request with many options |
| Add behavior at runtime | Decorator | Compression, encryption wrappers |
| Make incompatible things work | Adapter | Legacy API integration |
| Notify multiple observers | Observer | Event handling, MVC |
5. How does garbage collection work?¶
View Answer
GC Process
- Mark: Identify reachable objects from GC roots
- Sweep: Free unreachable objects
- Compact: Defragment heap (some algorithms)
GC Algorithms
| Algorithm | Latency | Throughput | Best For |
|---|---|---|---|
| Serial GC | High pauses | Good | Single-core, small heaps |
| Parallel GC | Medium pauses | Best | Batch processing |
| G1GC | Low pauses | Good | Large heaps, low latency |
| ZGC | Very low (<10ms) | Good | Ultra-low latency apps |
Generational Hypothesis
Most objects die young; old objects rarely become garbage.
✅ Optimize for young generation garbage collection.
6. What's the difference between type erasure and generics?¶
View Answer
Generics: Compile-Time Type Safety
List<String> list = new ArrayList<>();
list.add("Hello");
String s = list.get(0); // No cast needed, type-safe
Type Erasure: Runtime Behavior
Generics info ERASED at runtime.
// At compile-time (generic)
List<String> stringList = new ArrayList<>();
// At runtime (erased)
List stringList = new ArrayList(); // Type info gone!
Implications
// ❌ INVALID: Runtime doesn't know generic type
List<String> list = new ArrayList<>();
if (list instanceof List<String>) { } // Compile error
// ✅ Valid: Can check raw type
if (list instanceof List) { }
Why Type Erasure?
- Backward compatibility with pre-Java 5 code
- Reduce runtime memory (no type info stored)
PECS Principle: Producer Extends, Consumer Super
7. How do you identify and fix performance bottlenecks?¶
View Answer
Identification Steps
- Profile: Measure CPU, memory, I/O usage
- Find hotspot: Identify slowest method/component
- Measure baseline: Before/after comparison
- Iterate: Fix one issue at a time
Profiling Tools
- JProfiler: CPU/memory profiling
- YourKit: Advanced performance analysis
- Async Profiler: Low-overhead sampling
- JMH: Microbenchmarking
Common Bottlenecks & Fixes
| Issue | Symptoms | Fix |
|---|---|---|
| GC pauses | High latency spikes | Tune heap, use low-latency GC (ZGC) |
| Lock contention | High thread wait time | Use ConcurrentHashMap, lock-free structures |
| Database queries | Slow response time | Add indexes, optimize SQL, cache |
| N+1 problem | Many queries, slow | Use JOIN FETCH, entity graphs |
| Memory leaks | Growing heap, OOM | Profile, fix reference leaks |
8. Explain the decorator pattern with examples¶
View Answer
Decorator Pattern: Add Behavior Dynamically
Wrap objects to add behavior without modifying original class.
Example: Coffee Shop
// Base interface
interface Coffee {
double cost();
String description();
}
// Concrete implementation
class SimpleCoffee implements Coffee {
public double cost() { return 2.0; }
public String description() { return "Simple Coffee"; }
}
// Decorator
abstract class CoffeeDecorator implements Coffee {
protected Coffee coffee;
public CoffeeDecorator(Coffee coffee) { this.coffee = coffee; }
}
// Concrete decorators
class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee coffee) { super(coffee); }
public double cost() { return coffee.cost() + 0.5; }
public String description() { return coffee.description() + ", Milk"; }
}
class SugarDecorator extends CoffeeDecorator {
public SugarDecorator(Coffee coffee) { super(coffee); }
public double cost() { return coffee.cost() + 0.2; }
public String description() { return coffee.description() + ", Sugar"; }
}
Usage
Coffee coffee = new SimpleCoffee(); // $2.0
coffee = new MilkDecorator(coffee); // $2.5
coffee = new SugarDecorator(coffee); // $2.7
System.out.println(coffee.description()); // Simple Coffee, Milk, Sugar
System.out.println(coffee.cost()); // 2.7
Real-World Examples
- Java I/O: InputStream → BufferedInputStream → DataInputStream
- Spring: @Transactional decorator on methods
- Compression: FileOutputStream → GZIPOutputStream
Decorator vs Inheritance
Decorator: Combine at runtime, flexible, multiple decorators
Inheritance: Fixed at compile-time, rigid class hierarchy
See also: Design Patterns, Concurrency, Interview Questions Overview