Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
18 views

Java

Uploaded by

shaswatrai2001
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
18 views

Java

Uploaded by

shaswatrai2001
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 11

JAVA

1. What role does the “transient” keyword serve in JAVA, and how can it
be implemented effectively ?

In Java, "transient" keyword excludes a field from object serialization. Serialization


converts object state into bytes for storage or transmission. Marking a field as
transient tells Java not to serialize its value.

public class MyClass implements Serializable {


private int myInt;
private transient String myTransientString;
// Constructor, getters, and setters are ignored for simplicity
// Other methods…
}

In this example, "myTransientString" is marked transient, indicating exclusion


from serialization in MyClass instances.

2. Distinguish between "Inheritance" and "Composition" in object-


oriented programming, elucidating with a practical example to
highlight their disparities.

Inheritance involves creating a new class by inheriting properties from an existing


class, forming an "is-a" relationship between them. Composition, on the other hand,
involves a class containing instances of another class as its fields, establishing a "has-
a" relationship.

OR

In object-oriented programming, inheritance establishes a relationship where a


subclass derives properties from a superclass, forming an "is-a" relationship. It
enables code reuse and abstraction by inheriting methods and fields. On the other
hand, composition creates a "has-a" relationship by containing instances of another
class as fields. It fosters code reuse by encapsulating objects within objects,
promoting flexibility and modularity in software design.

● Inheritance example: The Vehicle class extends the Engine class, inheriting its fields and
methods. This establishes an "is-a" relationship, where Vehicle "is a" type of Engine.
public class Vehicle extends Engine {
// Fields and methods specific to the Vehicle class
}
● Composition example: The Vehicle class holds an Engine class instance as its
field, forming a "has-a" relationship. This means that Vehicle "has a" an Engine.

public class Vehicle {


private Engine engine;
public Vehicle(Engine engine) {
this.engine = engine;
}
// Methods that use the Engine instance
}

3. What output does the code below produce, and what is the reason
behind it?

public class TestClass {


public static void main(String[] args) {
someMethod(null);
}
public static void someMethod(Object o) {
System.out.println("Object method Invoked");
}
public static void someMethod(String s) {
System.out.println("String method Invoked");
}
}

The code output is "String method Invoked." In Java, null can be assigned

to any object reference type, but it's not an object itself. When overloading

methods, the Java compiler selects the most specific parameter type,

favoring the method with the String input parameter because it's more

specific than the Object parameter.

4. What sets apart a "Reader-Writer" lock from a


"ReentrantReadWriteLock" in Java? And which of the two offers greater
flexibility in usage?

A reader-writer lock allows multiple threads to read a shared resource


simultaneously, but only one thread can write to it at a time. With this lock, when
a thread wants to write, it must wait for all readers to finish before it can access
the resource.

On the other hand, ReentrantReadWriteLock is more flexible. It allows multiple


threads to hold the read lock simultaneously and lets a thread holding the read
lock acquire the write lock without releasing the read lock first. It's also reentrant,
meaning a thread holding the lock can acquire it again without releasing it first.
In simpler terms, ReentrantReadWriteLock offers more control and flexibility but
is more complex and can lead to deadlocks if misused. Reader-writer locks are
simpler and suitable for straightforward scenarios.

5. Suppose you have a computer with two drives, each containing


numerous nested folders, some of which have files in them. Could you
create a Java program to determine if a specific file exists within this
file structure? Additionally, how could you design the program to
minimize the time it takes to search for any given file?

import java.io.File;

class FileSearchThread extends Thread {

//File name and File Directory for every thread

private final String fileName;

private final File directory;

//Constuctor

public FileSearchThread(String fileName, File directory) {

this.fileName = fileName;

this.directory = directory;

//Run method that calls search method for searching file.

@Override

public void run() {

boolean result = searchFile(fileName, directory);

if(result) {

System.out.println(“File Found. Location — “ + directory.toString());

private boolean searchFile(String fileName, File directory) {

//Searching in the directory

File[] files = directory.listFiles();

if (files != null) {

for (File file : files) {

if (file.isDirectory()) {
// Recursively search in nested directories

searchFile(fileName, file);

} else if (file.getName().equalsIgnoreCase(fileName)) {

System.out.println(“File found at: “ +


file.getAbsolutePath());

return true;

return false;

public class FileSearch {

public static void main(String[] args) {

String fileNameToSearch = “xyz.txt”;

// Create a separate thread for each drive and folder

for (char drive = ‘C’; drive <= ‘D’; drive++) {

String rootPath = drive + “:\\”;

File[] directories = new File(rootPath).listFiles(File::isDirectory);

if (directories != null) {

for (File directory : directories) {

new FileSearchThread(fileNameToSearch, directory).start();

We create a Java program using a class named "FileSearchThread" that extends


Thread. It takes a file name and directory path as parameters. In the run method,
it recursively searches for the file in the given directory and its nested directories.
If found, it prints the absolute path and returns.
Then, in the "FileSearch" class, we iterate through the directories of drives C and D,
creating a separate thread for each drive and folder. We pass the file name to
search and the current directory to the FileSearchThread constructor, then start
the thread.

This approach allows us to search for the file in parallel, reducing the overall
search time.

6. Concurrent Hash Map Implementation

Solution: ConcurrentHashMap Implementation


Below is a simplified version of a concurrent hash map implemented in
Java. This solution uses synchronization to ensure thread safety.

import java.util.HashMap;

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ConcurrentHashMap<K, V> {

private final HashMap<K, V> map = new HashMap<>();

private final ReentrantReadWriteLock lock = new


ReentrantReadWriteLock();

public void put(K key, V value) {

lock.writeLock().lock();

try {

map.put(key, value);

} finally {

lock.writeLock().unlock();

public V get(K key) {

lock.readLock().lock();

try {

return map.get(key);

} finally {

lock.readLock().unlock();

}
public boolean containsKey(K key) {

lock.readLock().lock();

try {

return map.containsKey(key);

} finally {

lock.readLock().unlock();

public int size() {

lock.readLock().lock();

try {

return map.size();

} finally {

lock.readLock().unlock();

This implementation employs a ReentrantReadWriteLock to manage


concurrent access. Multiple threads can read simultaneously, but only one
thread can write at a time, ensuring data consistency. While effective for
basic thread safety, advanced optimizations like lock striping or fine-grained
locking can enhance performance. Addressing complex scenarios such as
atomic updates or managing concurrent modifications during iteration
would necessitate more sophisticated solutions.

7. Design a caching system in Java that can handle many requests


at once. This cache should support operations like adding data,
retrieving data, and deleting data. It should also automatically
remove data after a certain time and make sure it doesn't use too
much memory. Make sure your solution can be used on multiple
computers and that it's safe to use with multiple requests
happening at the same time.
import java.util.Map;

import java.util.concurrent.ConcurrentHashMap;

import java.util.concurrent.TimeUnit;

public class DistributedCache<K, V> {

private final Map<K, CacheEntry<V>> cache;

public DistributedCache() {

this.cache = new ConcurrentHashMap<>();

public void put(K key, V value, long expirationTime, TimeUnit timeUnit) {

long expirationMillis = System.currentTimeMillis() +


timeUnit.toMillis(expirationTime);

CacheEntry<V> entry = new CacheEntry<>(value, expirationMillis);

cache.put(key, entry);

public V get(K key) {

CacheEntry<V> entry = cache.get(key);

if (entry != null && !entry.isExpired()) {

return entry.getValue();

return null;

public void delete(K key) {

cache.remove(key);

private static class CacheEntry<V> {

private final V value;

private final long expirationTime;

CacheEntry(V value, long expirationTime) {

this.value = value;
this.expirationTime = expirationTime;

V getValue() {

return value;

boolean isExpired() {

return System.currentTimeMillis() >= expirationTime;

This implementation employs a ConcurrentHashMap for storing cache entries,


ensuring thread-safe access. Each entry is encapsulated within a CacheEntry
class, containing the value and expiration time. The put method inserts an entry
into the cache with a set expiration time. Conversely, the get method retrieves the
value only if it hasn't expired. The delete method removes an entry from the
cache. This distributed cache is deployable across multiple nodes, catering to the
caching needs of expansive applications efficiently.

8. Discuss the principles of object immutability in Java. When should


you design immutable objects, and what are the benefits of
immutability in concurrent programming?

Principles of Object Immutability in Java:

1. Final Fields: Immutable objects have fields declared as final, preventing


changes after initialization.

2. No Setters: They lack setter methods, with state initialized through


constructors and accessed through methods.

3. Deep Copy: If containing mutable objects, immutables create deep copies


during initialization to maintain immutability.

When to Design Immutable Objects:

1. Thread Safety: Immutables simplify concurrent programming as they're


inherently thread-safe, needing no synchronization.

2. Predictable Behavior: With unchangeable state, immutables offer


predictable behavior, aiding debugging and testing.

3. Cacheability: Immutable objects can be cached efficiently due to their


unchanging nature, improving performance.

4. Defensive Programming: They discourage unintended state modification,


promoting cleaner, more bug-resistant code.
Benefits of Immutability in Concurrent Programming:

1. Synchronization-Free: Immutable objects can be shared safely across


threads without synchronization, reducing complexity.

2. Parallelism: They enable efficient parallel processing by allowing concurrent


operations without interference.

3. Reduced Complexity: Immutables simplify concurrent programming,


making code more understandable and maintainable.

9. JVM tuning enhances Java application performance by adjusting


parameters like memory usage, garbage collection, and thread
management within the JVM. Common tuning parameters include heap
size, garbage collection settings, JIT compiler options, and thread
management parameters.
JVM tuning and optimization involve adjusting settings within the Java Virtual
Machine to enhance performance and efficiency. Here are some key parameters
commonly used:
1. Heap Size:
● `-Xms` (initial heap size) and `-Xmx` (maximum heap size): Control
memory allocation. Adjust to prevent OutOfMemory errors and
optimize memory usage.
2. Garbage Collection:
● `-XX:+UseG1GC:` Enables a garbage collector that balances
throughput and pause times.
● `-XX:MaxGCPauseMillis:` Sets the maximum desired pause time for
garbage collection.
3. Just-In-Time (JIT) Compiler:
● `-XX:+TieredCompilation:` Improves startup time and peak
performance by dynamically optimizing frequently executed code.
4. Thread Management:
● `-XX:ParallelGCThreads:` Adjusts the number of threads for garbage
collection to optimize throughput.
● `-XX:CICompilerCount:` Controls the number of compiler threads used
by the JIT compiler.
5. Class Data Sharing (CDS):
● `-Xshare:dump:` Reduces startup time and memory footprint by
sharing common class metadata and bytecode.
6. Profiling:
● `-XX:+PrintCompilation:` Helps identify frequently executed code for
optimization.
● `-XX:+PrintGC:` Aids in garbage collection tuning and memory issue
debugging.
● `-XX:+HeapDumpOnOutOfMemoryError:` Generates heap dumps for
memory analysis on OutOfMemoryError.
7. Miscellaneous:
● `-XX:MaxInlineLevel:` Controls the depth of inlining for better code
performance.
● `-XX:MaxRAMFraction:` Sets the fraction of system memory used for
the Java heap.

10. Problem: Implement a thread-safe singleton class in Java.


Requirements:

1. The singleton class should be thread-safe, meaning it should work


correctly in a multi-threaded environment without any race
conditions.

2. The singleton instance should be lazily initialized.

3. Your solution should be efficient and scalable.

4. Avoid using synchronization wherever possible to minimize


performance overhead.

5. Ensure that the solution adheres to best practices and design


principles.

Starting point for the candidate ➖


public class ThreadSafeSingleton {

// TODO: Implement the singleton instance variable

private ThreadSafeSingleton() {

// TODO: Initialize the singleton instance

// TODO: Implement a method to get the singleton


instance

// TODO: Implement any additional methods or variables


as needed

// TODO: Implement the logic to ensure thread safety

Solution :
public class ThreadSafeSingleton {

private static volatile ThreadSafeSingleton instance;

private ThreadSafeSingleton() {

// Private constructor to prevent instantiation from outside

public static ThreadSafeSingleton getInstance() {

if (instance == null) {

synchronized (ThreadSafeSingleton.class) {

if (instance == null) {
instance = new ThreadSafeSingleton();

return instance;

// Additional methods or variables can be added here

Explanation :
1. The class has a private constructor to prevent instantiation from
outside the class.
2. The instance variable is declared as volatile to ensure that changes
made by one thread are immediately visible to other threads.
3. The getInstance() method checks if the instance is null, and if so, it
enters a synchronized block to prevent multiple threads from creating
multiple instances simultaneously.
4. Inside the synchronized block, it checks again if the instance is null to
handle the race condition that might occur if multiple threads reach
the synchronized block at the same time.
5. If the instance is still null inside the synchronized block, it creates a
new instance of the singleton class.
6. Finally, it returns the singleton instance.

You might also like