141. What is java.lang.reflect.Proxy used for in Java?
Answer:
java.lang.reflect.Proxy is used for creating dynamic proxy instances at runtime that implement specified interfaces. This enables method calls on proxy instances to be forwarded to an invocation handler, making it highly useful in Aspect-Oriented Programming (AOP) and popular frameworks like Spring. Proxies help in creating flexible and reusable code by intercepting method calls for tasks such as logging, security, and transaction management.
Q142. What are some advanced features of CompletableFuture in Java?
Answer:
CompletableFuture in Java offers powerful asynchronous programming capabilities including:
- Chaining multiple asynchronous tasks for complex workflows
- Combining several async computations and merging their results
- Handling exceptions gracefully in async chains
- Implementing timeouts and providing default values if tasks take too long
- Customizing thread execution using custom executors
These features make CompletableFuture a key tool for concurrent programming in modern Java applications.
Q143. What is ForkJoinPool, and how does it differ from a regular thread pool?
Answer:
ForkJoinPool (introduced in Java 7) is a specialized thread pool designed for efficient parallel processing of recursive tasks using the work-stealing algorithm. Differences include:
Feature | ForkJoinPool | Regular Thread Pool |
Task Type | Recursive, divide-and-conquer (e.g., RecursiveTask) | Independent Runnable or Callable tasks |
Work Stealing | Yes – idle threads steal tasks from busy threads | No work stealing |
Use Case | CPU-intensive, recursive tasks like parallel sorting | I/O-bound or independent tasks |
Task Splitting | Supports splitting via fork() and join() | No built-in splitting |
Performance | Optimized for parallel execution across CPU cores | Suitable for asynchronous but not parallel optimization |
Q144. How does the Unsafe class work, and what are its use cases?
Answer:
The Unsafe class (found in sun.misc.Unsafe) provides low-level, unsafe operations like direct memory access and atomic operations, bypassing standard Java safety checks. Key functionalities include:
- Allocating and freeing memory manually
- Creating objects without invoking constructors
- Performing CAS (Compare-And-Swap) operations for atomic updates
- Manipulating threads and class loading dynamically
Use cases: high-performance libraries (e.g., Netty), off-heap memory management to reduce GC overhead, atomic variable implementations, and internal JVM hacks. Despite its power, it should be used with caution due to potential instability.
Q145. What is a PhantomReference in Java, and when is it used?
Answer:
PhantomReference is a reference type from java.lang.ref that allows developers to perform post-mortem cleanup after an object has been finalized but before memory is reclaimed. Unlike WeakReference and SoftReference, PhantomReference.get() always returns null. It is enqueued in a ReferenceQueue for cleanup tasks such as deallocating native resources, ensuring proper release of resources beyond what the GC handles automatically.
Q146. Explain the concept of MethodHandle in Java.
Answer:
MethodHandle (introduced in Java 7 under java.lang.invoke) is a lightweight, type-safe mechanism to dynamically invoke methods, constructors, or access fields, offering better performance than reflection (java.lang.reflect.Method). It supports invoking private, static, and instance methods with compile-time type checking. It’s widely used internally for lambda expressions and JVM optimizations like invokedynamic. Use MethodHandle when you need efficient dynamic method invocation in performance-critical applications.
Q147. What is the role of the java.lang.instrument package?
Answer:
The java.lang.instrument package allows runtime bytecode modification through Java agents. It is widely used for profiling, monitoring, and aspect-oriented programming by enabling modification of class definitions as they are loaded by the JVM. This package is crucial for advanced tools that require instrumentation without altering the source code.
Q148. How does the Java Memory Model handle out-of-order execution and memory visibility?
Answer:
The Java Memory Model (JMM) defines strict rules for happens-before relationships to guarantee correct memory visibility between threads. It uses volatile variables and synchronization (synchronized blocks) to enforce ordering constraints and prevent compiler and CPU reordering optimizations that could break concurrency semantics. This ensures that changes made by one thread become visible to others in a predictable manner.
Q149. What is the difference between ReentrantLock and synchronized in Java?
Answer:
Feature | synchronized | ReentrantLock |
API | Built-in monitor lock | Part of java.util.concurrent.locks |
Lock/Unlock | Automatic | Explicit lock() and unlock() |
Try Lock | Not supported | Supports tryLock() and timed locking |
Fairness | No fairness guarantee | Can be fair (new ReentrantLock(true)) or unfair |
Interruptibility | Not interruptible | Supports lockInterruptibly() |
Condition Support | Uses wait()/notify() | Provides Condition variables for fine-grained control |
Complexity | Simpler to use | More powerful but requires careful management |
Q150. What is the difference between WeakReference and SoftReference in Java?
Answer:
Both WeakReference and SoftReference help manage memory by allowing the garbage collector to reclaim referenced objects under different conditions:
Aspect | WeakReference | SoftReference |
Garbage Collection | Reclaimed immediately when no strong references exist | Reclaimed only under memory pressure |
Retention | Short-lived, aggressively cleared | Longer-lived, retained until JVM needs memory |
Use Cases | Lookup caches, avoiding memory leaks | Cache data that is expensive to reload (e.g., images) |
GC Behavior | Cleared at earliest GC opportunity | Cleared only when memory is low |
Likelihood of Collection | Very high | Lower, kept as long as possible |