Set 2
What are the features of JAVA?
Features of Java are as follows:
OOP concepts
Object-oriented
Inheritance
Encapsulation
Polymorphism
Abstraction
Platform independent: A single program works on different platforms without any modification.
High Performance: JIT (Just In Time compiler) enables high performance in Java. JIT converts the bytecode into machine language and then JVM starts the execution.
Multi-threaded: A flow of execution is known as a Thread. JVM creates a thread which is called the main thread. The user can create multiple threads by extending the thread class or by implementing the Runnable interface.
How does Java enable high performance?
Java uses Just In Time compiler to enable high performance. It is used to convert the instructions into bytecodes.
What is Inheritance?
Inheritance means one class can extend to another class. So that the codes can be reused from one class to another class. The existing class is known as the Super class whereas the derived class is known as a sub class.
What is Encapsulation?
Purpose of Encapsulation:
Protects the code from others.
Code maintainability.
We are declaring ‘a’ as an integer variable and it should not be negative.
If someone changes the exact variable as “a = -5” then it is bad.
In order to overcome the problem we need to follow the steps below:
We can make the variable private or protected.
Use public accessor methods such as set<property> and get<property>.
So that the above code can be modified as:
For encapsulation, we need to make all the instance variables private and create setter and getter for those variables. Which in turn will force others to call the setters rather than access the data directly.
What is Polymorphism?
Polymorphism means many forms. Polymorphism is applicable for overriding and not for overloading.
What is meant by Interface?
Multiple inheritances cannot be achieved in java. To overcome this problem the Interface concept is introduced. An interface in Java is a template or reference type, similar to a class, that can contain only constants, method signatures, default methods, static methods, and nested types. Interfaces cannot contain instance fields or constructors. Java does not support multiple inheritance (i.e., a class cannot inherit from more than one class) to avoid complexity and ambiguity (such as the Diamond Problem). However, multiple inheritance of type is achieved by using interfaces. A class can implement multiple interfaces, thus providing a way to achieve multiple inheritances.
All the methods in the interface are internally public abstract void.
All the variables in the interface are internally public static final that is constants.
Classes can implement the interface and not extends.
The class which implements the interface should provide an implementation for all the methods declared in the interface.
What is meant by Abstract class?
An abstract class in Java is a class that cannot be instantiated on its own and is intended to be subclassed by other classes. It is used to define common characteristics and behaviors that multiple derived classes can share, but it can also include abstract methods that must be implemented by the subclasses.
Cannot Be Instantiated: You cannot create an instance of an abstract class.
Can Contain Abstract Methods: These are methods declared without an implementation. Subclasses must provide implementations for these methods.
Can Contain Concrete Methods: These are methods with an implementation. Subclasses can use or override these methods.
Can Have Constructors: Although you cannot instantiate an abstract class, you can define constructors in it, and these constructors are called when an instance of a subclass is created.
Can Have Fields and Methods: Just like regular classes, abstract classes can have member variables and methods.
Can Implement Interfaces: Abstract classes can implement interfaces, and the implementing subclasses must provide implementations for the interface methods.
Difference between Array and Array List
Definition
A fixed-size data structure that holds elements of the same type.
A resizable array implementation of the List interface.
Size
Fixed size, determined at the time of creation.
Dynamic size, can grow or shrink as needed.
Performance
Faster for indexed access and manipulation due to fixed size.
Slower for indexed access compared to arrays due to resizing and potential overhead.
Flexibility
Less flexible; size cannot be changed after creation.
More flexible; can change size dynamically.
Initialization
int[] arr = new int[10];
ArrayList<Integer> list = new ArrayList<>();
Element Type
Can hold primitive types or objects.
Can only hold objects (wrapper classes for primitives).
Memory Management
Continuous memory allocation.
Non-continuous memory allocation; uses an internal array that grows as needed.
Methods Available
Limited to basic operations (e.g., length, clone).
Extensive methods from the List interface (e.g., add, remove, get, size, contains).
Iteration
Requires loop constructs like for, while.
Supports enhanced for-loop and iterator.
Type Safety
Type-safe with primitive types and objects.
Type-safe with generics; can enforce type constraints.
Null Values
Can hold null values.
Can hold null values.
Use Case
Best for fixed-size collections where performance is critical.
Best for dynamic collections where the size may change frequently.
Example
int[] numbers = {1, 2, 3, 4, 5};
ArrayList<Integer> numbers = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
Multidimensional
Supports multidimensional arrays (e.g., int[][] matrix
).
Supports only single-dimensional ArrayLists; multidimensional behavior achieved with nested ArrayLists.
Capacity Management
No concept of capacity; fixed size.
Initial capacity can be specified; grows automatically when capacity is exceeded.
Primitive Handling
Directly stores primitive types.
Requires boxing/unboxing for primitive types (e.g., int
to Integer
).
Difference between HashMap and HashTable
Thread Safety
Not thread-safe
Thread-safe
Synchronization
No methods are synchronized
All methods are synchronized
Performance
Faster due to lack of synchronization
Slower due to synchronization overhead
Null Keys and Values
Allows one null key and multiple null values
Does not allow null keys or null values
Legacy
Part of the Java Collections Framework
Legacy class (exists since JDK 1.0)
Iteration Order
Does not guarantee any specific order
Does not guarantee any specific order
Initial Capacity and Load Factor
Default initial capacity of 16 and load factor of 0.75
Initial capacity is 11 and load factor is 0.75
Fail-Fast Iterator
Yes, throws ConcurrentModificationException
if the map is modified while iterating
Yes, but the behavior is undefined
Use Case
Best for non-threaded applications
Best for legacy applications requiring thread safety
Example Initialization
HashMap<String, Integer> map = new HashMap<>();
Hashtable<String, Integer> table = new Hashtable<>();
Synchronization Control
Can be synchronized externally using Collections.synchronizedMap(new HashMap<>());
Internally synchronized, cannot be made non-synchronized
Difference between HashSet and TreeSet
Underlying Data Structure
Hash table
Red-Black tree (a type of self-balancing binary search tree)
Order of Elements
No guaranteed order
Elements are sorted in natural order or by a provided comparator
Performance (Basic Operations)
O(1) average time complexity for add, remove, and contains operations
O(log n) time complexity for add, remove, and contains operations
Null Elements
Allows a single null element
Does not allow null elements (throws NullPointerException
)
Duplicates
Does not allow duplicate elements
Does not allow duplicate elements
Iteration Order
No guaranteed iteration order
Iterates in ascending order
Comparator Support
No
Yes, can use a custom comparator for sorting
Methods for Range Operations
No
Yes, provides methods like subSet()
, headSet()
, tailSet()
Example Initialization
Set<String> set = new HashSet<>();
Set<String> set = new TreeSet<>();
Use Case
Best for collections with unique elements and no ordering requirement
Best for collections with unique elements that need to be sorted
Difference between Abstract class and Interface
Definition
Can contain abstract and concrete methods.
Can only contain abstract methods (until Java 8). From Java 8 onwards, can contain default and static methods.
Purpose
To provide a common base class with shared code.
To define a contract that implementing classes must follow.
Inheritance
A class can inherit only one abstract class (single inheritance).
A class can implement multiple interfaces (multiple inheritance).
Implementation
Can provide method implementations.
Cannot provide method implementations (except default and static methods from Java 8 onwards).
Fields
Can have instance variables (fields) and static fields.
Can only have static final fields (constants).
Constructors
Can have constructors.
Cannot have constructors.
Access Modifiers
Can have any access modifier (public, protected, private).
Methods are implicitly public (until Java 9). Can have private methods from Java 9 onwards.
When to Use
When you want to share code among several closely related classes.
When you want to define a role that can be shared among classes not necessarily related.
Multiple Inheritance
Does not support multiple inheritance.
Supports multiple inheritance.
Example Usage
abstract class Animal { ... }
interface AnimalBehavior { ... }
Method Implementation
Can contain both abstract and concrete methods.
Can contain abstract methods, and from Java 8 onwards, default and static methods.
State Management
Can manage state via instance variables.
Cannot manage state, only constants.
Instantiation
Cannot be instantiated directly.
Cannot be instantiated directly.
What is Java Collections Framework?
The Java Collections Framework is a unified architecture for representing and manipulating collections of objects. It includes interfaces, implementations, and algorithms to help developers work with groups of objects in a standard way. The key components of the Java Collections Framework are:
Interfaces
These are abstract data types that represent collections. Some of the primary interfaces include:
Collection: The root interface in the collection hierarchy. A collection represents a group of objects known as its elements.
List: An ordered collection (also known as a sequence). Allows duplicate elements. Examples:
ArrayList
,LinkedList
.Set: A collection that does not allow duplicate elements. Examples:
HashSet
,TreeSet
.Queue: A collection designed for holding elements prior to processing. Examples:
PriorityQueue
,LinkedList
.Deque: A double-ended queue that allows elements to be added or removed from both ends. Examples:
ArrayDeque
,LinkedList
.
Map: An object that maps keys to values. A map cannot contain duplicate keys; each key can map to at most one value. Examples:
HashMap
,TreeMap
,Hashtable
.
Implementations
These are the concrete classes that implement the collection interfaces. Some examples include:
ArrayList: Implements the
List
interface. Uses a dynamic array to store elements.LinkedList: Implements both
List
andDeque
interfaces. Uses a doubly linked list to store elements.HashSet: Implements the
Set
interface. Uses a hash table for storage.TreeSet: Implements the
Set
interface. Uses a Red-Black tree for storage, which orders the elements.HashMap: Implements the
Map
interface. Uses a hash table for storage.TreeMap: Implements the
Map
interface. Uses a Red-Black tree for storage, which orders the keys.
Algorithms
These are methods that perform useful computations, such as searching and sorting, on objects that implement collection interfaces. These algorithms are defined as static methods within the java.util.Collections
class.
java.util.Collections
Class
java.util.Collections
ClassThe java.util.Collections
class consists of static methods that operate on or return collections. It contains polymorphic algorithms that operate on collections, "wrappers" which return a new collection backed by a specified collection, and a few other odds and ends.
Key Methods in java.util.Collections
Sorting:
sort(List<T> list)
: Sorts the specified list into ascending order.sort(List<T> list, Comparator<? super T> c)
: Sorts the specified list according to the order induced by the specified comparator.
Searching:
binarySearch(List<? extends T> list, T key)
: Searches the specified list for the specified object using the binary search algorithm.binarySearch(List<? extends T> list, T key, Comparator<? super T> c)
: Searches the specified list for the specified object using the binary search algorithm and a comparator.
Shuffling:
shuffle(List<?> list)
: Randomly permutes the specified list.shuffle(List<?> list, Random rnd)
: Randomly permutes the specified list using the specified source of randomness.
Synchronization:
synchronizedCollection(Collection<T> c)
: Returns a synchronized (thread-safe) collection backed by the specified collection.synchronizedList(List<T> list)
: Returns a synchronized (thread-safe) list backed by the specified list.synchronizedMap(Map<K,V> m)
: Returns a synchronized (thread-safe) map backed by the specified map.
Unmodifiable Collections:
unmodifiableCollection(Collection<? extends T> c)
: Returns an unmodifiable view of the specified collection.unmodifiableList(List<? extends T> list)
: Returns an unmodifiable view of the specified list.unmodifiableMap(Map<? extends K,? extends V> m)
: Returns an unmodifiable view of the specified map.
Explain the different lists available in the collection?
In the Java Collections Framework, the List
interface is a part of the java.util
package and represents an ordered collection (also known as a sequence). The List
interface extends the Collection
interface and includes operations for positional access, searching, iteration, and range-view. Various implementations of the List
interface provide different ways of storing and managing the elements. Here are the main List
implementations available:
1. ArrayList
ArrayList
Description:
Implements the
List
interface using a dynamically resizable array.Provides fast random access to elements.
Key Characteristics:
Resizing: Automatically grows when elements are added beyond its capacity.
Performance: O(1) time complexity for positional access. O(n) for add/remove operations when resizing is necessary.
Nulls: Allows null elements.
Use Case: Suitable for frequent read operations and occasional insertions and deletions.
2. LinkedList
LinkedList
Description:
Implements the
List
interface using a doubly linked list.Provides efficient insertion and removal of elements.
Key Characteristics:
Structure: Each element (node) contains a reference to the previous and next elements.
Performance: O(1) time complexity for insertions and deletions at the beginning or end. O(n) for positional access.
Nulls: Allows null elements.
Use Case: Suitable for applications that require frequent insertions and deletions, particularly at the beginning or end of the list.
3. Vector
Vector
Description:
Implements the
List
interface using a dynamically resizable array, similar toArrayList
.Synchronized, making it thread-safe.
Key Characteristics:
Thread-Safety: All methods are synchronized.
Performance: O(1) time complexity for positional access. Slower than
ArrayList
due to synchronization overhead.Nulls: Allows null elements.
Use Case: Suitable for legacy codebases and applications requiring thread-safe list operations.
4. Stack
Stack
Description:
A subclass of
Vector
that implements a last-in-first-out (LIFO) stack.
Key Characteristics:
LIFO: Provides typical stack operations like
push
,pop
, andpeek
.Performance: Similar to
Vector
.Nulls: Allows null elements.
Use Case: Suitable for stack operations and legacy applications requiring stack functionalities.
5. CopyOnWriteArrayList
CopyOnWriteArrayList
Description:
A thread-safe variant of
ArrayList
in which all mutative operations (e.g., add, set, remove) are implemented by making a fresh copy of the underlying array.
Key Characteristics:
Thread-Safety: Thread-safe without using synchronization.
Performance: Efficient for read operations, but slower for write operations due to array copying.
Nulls: Allows null elements.
Use Case: Suitable for applications with many concurrent read operations and relatively few write operations.
Explain about Set and their types in a collection
In the Java Collections Framework, the Set
interface is a part of the java.util
package and represents a collection that does not allow duplicate elements. The Set
interface extends the Collection
interface. There are several implementations of the Set
interface, each providing different ways to store and manage elements. Here's a detailed look at the internals of Set
and its types:
Set
Interface
Set
InterfaceThe Set
interface defines a collection that does not allow duplicate elements. It models the mathematical set abstraction and provides methods for basic operations like adding, removing, and checking for elements. The primary implementations of the Set
interface include HashSet
, LinkedHashSet
, and TreeSet
.
1. HashSet
HashSet
Description:
Implements the
Set
interface using a hash table.Provides constant-time performance for basic operations (add, remove, contains).
Internals:
Uses a
HashMap
internally to store elements.Elements are stored as keys in the
HashMap
, with a dummy value.The hash code of the element is used to determine its position in the hash table.
Key Characteristics:
Order: No guaranteed order of elements.
Performance: O(1) average time complexity for basic operations.
Nulls: Allows a single null element.
Use Case: Suitable for collections where fast access is required, and the order of elements is not important.
2. LinkedHashSet
LinkedHashSet
Description:
Extends
HashSet
and maintains a linked list of the entries in the set.Provides insertion-order iteration.
Internals:
Uses a
LinkedHashMap
internally.Maintains a doubly linked list running through all of its entries to maintain insertion order.
Key Characteristics:
Order: Maintains insertion order of elements.
Performance: Slightly slower than
HashSet
due to the additional linked list.Nulls: Allows a single null element.
Use Case: Suitable for collections where fast access is required, but the order of elements needs to be preserved.
3. TreeSet
TreeSet
Description:
Implements the
Set
interface using a Red-Black tree (a self-balancing binary search tree).Provides sorted order of elements.
Internals:
Uses a
TreeMap
internally.Elements are stored as keys in the
TreeMap
.The tree is sorted according to the natural ordering of its elements or by a comparator provided at set creation time.
Key Characteristics:
Order: Elements are sorted in ascending order or by a provided comparator.
Performance: O(log n) time complexity for basic operations.
Nulls: Does not allow null elements (throws
NullPointerException
).
Use Case: Suitable for collections where sorted order of elements is required.
Explain about Map and its types?
In the Java Collections Framework, the Map
interface is a part of the java.util
package and represents a collection of key-value pairs. A Map
cannot contain duplicate keys, and each key can map to at most one value. There are several implementations of the Map
interface, each providing different ways to store and manage key-value pairs. Here's a detailed look at the Map
interface and its types:
Map
Interface
Map
InterfaceThe Map
interface defines a collection that maps keys to values. It includes methods for basic operations like putting, getting, removing, and checking for elements. The primary implementations of the Map
interface include HashMap
, LinkedHashMap
, TreeMap
, and Hashtable
.
1. HashMap
HashMap
Description:
Implements the
Map
interface using a hash table.Provides constant-time performance for basic operations (put, get, remove).
Internals:
Uses an array of buckets, where each bucket is a linked list (or tree in case of many collisions).
The hash code of the key is used to determine its position in the hash table.
Key Characteristics:
Order: No guaranteed order of keys.
Performance: O(1) average time complexity for basic operations.
Nulls: Allows one null key and multiple null values.
Use Case: Suitable for collections where fast access is required, and the order of keys is not important.
2. LinkedHashMap
LinkedHashMap
Description:
Extends
HashMap
and maintains a doubly linked list of the entries.Provides insertion-order iteration.
Internals:
Uses a hash table with a linked list running through all of its entries to maintain insertion order.
Key Characteristics:
Order: Maintains insertion order of keys.
Performance: Slightly slower than
HashMap
due to the additional linked list.Nulls: Allows one null key and multiple null values.
Use Case: Suitable for collections where fast access is required, but the order of keys needs to be preserved.
3. TreeMap
TreeMap
Description:
Implements the
Map
interface using a Red-Black tree (a self-balancing binary search tree).Provides sorted order of keys.
Internals:
Uses a tree structure where elements are sorted according to the natural ordering of its keys or by a comparator provided at map creation time.
Key Characteristics:
Order: Keys are sorted in ascending order or by a provided comparator.
Performance: O(log n) time complexity for basic operations.
Nulls: Does not allow null keys (throws
NullPointerException
).
Use Case: Suitable for collections where sorted order of keys is required.
4. Hashtable
Hashtable
Description:
Implements the
Map
interface using a hash table.Synchronized, making it thread-safe.
Internals:
Uses an array of buckets, where each bucket is a linked list.
The hash code of the key is used to determine its position in the hash table.
Key Characteristics:
Order: No guaranteed order of keys.
Performance: Slower than
HashMap
due to synchronization overhead.Nulls: Does not allow null keys or values (throws
NullPointerException
).
Use Case: Suitable for legacy applications requiring thread-safe map operations.
Explain the Priority Queue?
In the Java Collections Framework, PriorityQueue
is an implementation of the Queue
interface that provides a priority-based ordering of elements. Elements in a PriorityQueue
are ordered either by their natural ordering (if they implement the Comparable
interface) or by a comparator provided at queue construction time. This makes PriorityQueue
useful in scenarios where elements need to be processed based on their priority.
Key Features of PriorityQueue
:
PriorityQueue
:Priority Ordering:
Elements are ordered based on their priority, defined by either natural order or a custom comparator.
The head of the queue is always the least element with respect to the specified ordering.
Dynamic Size:
Unlike arrays or linked lists,
PriorityQueue
sizes can change dynamically as elements are added or removed.
Efficient Operations:
Basic operations like
add
,offer
,peek
, andpoll
have logarithmic time complexities (O(log n)
), wheren
is the number of elements in the queue.Removing the head (highest priority element) is efficient due to the underlying heap structure.
Internal Structure:
Internally, a PriorityQueue
uses a heap data structure, specifically a binary heap, to maintain the priority order of elements. In a binary heap:
Min-Heap: The smallest element is always at the root, making it suitable for
PriorityQueue
where the smallest element (by natural order or comparator) is dequeued first.Max-Heap: The largest element is at the root, which can be simulated by using a comparator that reverses the natural order.
Example Usage:
Use Cases:
Task Scheduling: Process tasks based on their priority (e.g., shortest job first in scheduling algorithms).
Event Handling: Handle events or notifications based on urgency or importance.
Graph Algorithms: Implement algorithms like Dijkstra's shortest path algorithm, where nodes are processed in order of their priority.
What is the final keyword in Java?
Final variable: Once a variable is declared as final, then the value of the variable could not be changed. It is like a constant.
Final method: A final keyword in a method, couldn’t be overridden. If a method is marked as a final, then it can’t be overridden by the subclass.
Final class: If a class is declared as final, then the class couldn’t be subclassed. No class can extend the final class.
What is a Thread? Different ways to create a thread?
In Java, a thread refers to the smallest unit of execution within a process. It allows concurrent execution of tasks, enabling programs to perform multiple operations simultaneously. Threads share memory space and resources within the same process, making them lightweight compared to processes.
Every java program has at least one thread called the main thread, the main thread is created by JVM. The user can define their own threads.
Ways to Create a Thread in Java
There are two main ways to create a thread in Java:
1. Extending the Thread
Class
You can create a thread by extending the Thread
class and overriding its run()
method, which contains the code that executes when the thread starts.
Example:
2. Implementing the Runnable
Interface
You can create a thread by implementing the Runnable
interface and providing an implementation for the run()
method. This approach separates the thread's behavior from the thread itself, allowing better code organization and reuse.
Example:
Key Points to Remember:
Both approaches (
Thread
subclass andRunnable
interface) achieve the same goal of creating a new thread.Implementing
Runnable
is generally preferred over extendingThread
because it allows better separation of concerns and allows the class to extend another class if needed.When a thread's
run()
method completes, the thread terminates unless specified otherwise.
Additional Considerations:
Lambda Expression (Java 8 and later): You can use lambda expressions to create and start a thread, especially when the thread logic is simple and can be expressed inline.
Example using lambda expression:
Executor Framework: Java provides higher-level concurrency utilities such as
ExecutorService
andThreadPoolExecutor
from thejava.util.concurrent
package, which manage thread execution more efficiently than creating threads manually.
Threads are fundamental to Java's support for concurrent programming, allowing developers to create applications that can perform tasks concurrently and efficiently utilize available resources.
Different Thread Methods
In Java, several methods are crucial for thread management and synchronization. Here's an overview of each method you mentioned:
1. join()
join()
The join()
method allows one thread to wait for the completion of another thread. When a thread calls join()
on another thread, it suspends its execution until the thread it joined completes its execution or a specified timeout occurs.
Example:
2. yield()
yield()
The yield()
method is a hint to the scheduler that the current thread is willing to yield its current use of the processor. It allows the scheduler to select another thread to run instead of the current thread. However, yielding is not guaranteed to have any effect on thread execution order.
Example:
3. wait()
, notify()
, notifyAll()
wait()
, notify()
, notifyAll()
These methods are used for inter-thread communication and synchronization using object monitors:
wait()
: Causes the current thread to wait until another thread invokes thenotify()
ornotifyAll()
method for this object or a specified timeout expires.notify()
: Wakes up a single thread that is waiting on this object's monitor. If multiple threads are waiting, one of them is chosen to be awakened.notifyAll()
: Wakes up all threads that are waiting on this object's monitor. This method should be used to notify waiting threads if multiple threads may be waiting for the same condition.
Example:
Other Methods
sleep(long milliseconds)
: Causes the current thread to sleep for the specified number of milliseconds. This method is used for pausing execution.interrupt()
: Interrupts the thread, causing it to exit from its waiting or sleeping state, throwing anInterruptedException
if it's waiting.isAlive()
: Checks if the thread is alive (i.e., started and not yet terminated).setDaemon(boolean on)
: Marks the thread as either a daemon thread (background thread) or a user thread. Daemon threads are terminated when all user threads have finished executing.
Different ways to stop or pause a thread
In Java, there are several ways to stop or pause a thread, each suited to different scenarios and requirements. Here are some common methods:
1. Thread.sleep(long milliseconds)
Thread.sleep(long milliseconds)
The Thread.sleep()
method pauses the execution of the current thread for the specified number of milliseconds. It can be used to introduce delays or pause execution temporarily.
Example:
2. Thread.yield()
Thread.yield()
The Thread.yield()
method is a hint to the scheduler that the current thread is willing to yield its current use of the processor. It allows the scheduler to select another thread to run instead of the current thread. However, its effectiveness can vary across different JVM implementations.
Example:
3. Thread.interrupt()
Thread.interrupt()
The Thread.interrupt()
method interrupts a thread that is currently in a waiting, sleeping, or blocking state. It causes the thread to throw an InterruptedException
or wake up from sleep.
Example:
4. Using a volatile flag or boolean variable
You can use a volatile
boolean flag or variable to control the execution of a thread. The thread periodically checks the flag and exits or pauses based on its value.
Example:
5. Using wait()
and notify()
wait()
and notify()
For more complex coordination between threads, you can use wait()
and notify()
methods for inter-thread communication and synchronization. This allows threads to pause and resume based on specific conditions.
Example:
When to use the Runnable interface Vs Thread class?
Aspect
Runnable
Interface
Extending Thread
Class
Inheritance
Does not require extending a specific class
Requires extending the Thread
class
Flexibility
Allows the class to extend another class if needed
Limits the class to only extending Thread
Code Reuse
Promotes better code organization and reusability
Limited reuse because the class extends Thread
directly
Separation of Concerns
Separates thread logic from the thread object itself
Combines thread logic with the thread object
Multiple Inheritance
Allows implementing multiple interfaces
Does not support multiple inheritance
Thread Pooling
Better suited for use with thread pools and executors
Less flexible with thread pools and executors
Concurrency
Encourages better synchronization practices
Requires careful handling of thread synchronization
Common Practice
Preferred approach in modern Java programming
Older style, still used in certain scenarios
Difference between start() and run() method of thread class
Aspect
start()
Method
run()
Method
Invocation
Invoked to start the execution of a new thread
Contains the actual code to be executed by the thread
Execution Context
Executes in a new thread context
Executes in the current thread context
Method Signature
public void start()
public void run()
Concurrency
Initiates thread creation and scheduling
Does not create a new thread; runs in current thread
Thread Lifecycle
Starts the thread lifecycle (NEW -> RUNNABLE)
No effect on thread lifecycle
Overriding
Should not be overridden
Should be overridden to define thread's task
Calling Sequence
Called once per thread instance
Called when start()
method is invoked
Execution Control
Returns immediately after starting the thread
Blocks until run()
method completes
Use Case
Use to initiate concurrent execution
Contains the task to be executed by the thread
Example
thread.start();
public void run() { /* task implementation */ }
Difference between Multi-threading and Parallel processing?
The terms "multi-threading" and "parallel processing" are related to concurrent execution in computing but refer to distinct concepts:
Multi-threading:
Definition: Multi-threading refers to the concurrent execution of multiple threads within the same process.
Concurrency: Threads share the same memory space and resources of the process.
Execution: Threads are managed by the operating system's thread scheduler, which allocates CPU time to each thread.
Communication: Threads within the same process can communicate directly via shared memory.
Use Cases:
Enhancing responsiveness in GUI applications by offloading long-running tasks to background threads.
Improving performance by overlapping I/O operations with computation.
Parallel Processing:
Definition: Parallel processing involves executing multiple tasks simultaneously across multiple processors or cores to achieve faster computations.
Concurrency: Tasks are executed independently and concurrently on different processors.
Execution: Typically involves distributing tasks across multiple CPUs or cores to achieve performance gains.
Communication: Processes in parallel processing may communicate via inter-process communication mechanisms or shared data structures.
Use Cases:
Scientific computing and simulations where large datasets are processed concurrently.
Big data analytics, where tasks can be divided and processed across multiple nodes in a cluster.
Key Differences:
Concurrency vs. Parallelism:
Concurrency (multi-threading) focuses on managing multiple tasks (threads) that may be executed in overlapping time periods within the same process.
Parallelism involves simultaneous execution of multiple tasks across different processors or cores, aiming for faster computation.
Resource Utilization:
Multi-threading primarily optimizes CPU and I/O resource utilization within a single computing unit (e.g., a single machine or node).
Parallel processing utilizes multiple computing units (CPUs/cores) to divide and conquer tasks for higher throughput.
Communication Overhead:
Multi-threading benefits from low communication overhead as threads share memory space.
Parallel processing across multiple processors or nodes may involve higher communication overhead due to inter-process communication.
Example Scenario:
Multi-threading:
A web server handling multiple client requests concurrently using threads to manage each request's I/O and computation tasks.
Parallel Processing:
A data analytics platform processing vast amounts of data by distributing computation across multiple nodes in a cluster, leveraging parallelism to achieve faster data processing.
Explain the thread life cycle in Java.
The thread life cycle in Java describes the various states a thread transitions through during its execution. Here’s a concise explanation of the thread life cycle stages:
New:
A thread begins its life cycle in the
New
state when an instance of theThread
class is created butstart()
method is not yet invoked.
Runnable:
After invoking the
start()
method, the thread moves to theRunnable
state.In this state, the thread is ready to run, but it may not be currently executing due to CPU scheduling.
Running:
The thread enters the
Running
state when the CPU scheduler selects it to execute.It executes its task within this state until it voluntarily relinquishes CPU control or is preempted by a higher-priority thread.
Blocked/Waiting:
A thread can transition to the
Blocked
orWaiting
state under certain conditions:Blocked: When waiting for a monitor lock to enter a synchronized block or method.
Waiting: When waiting indefinitely for another thread to perform a specific action, such as calling
wait()
orjoin()
methods.
Timed Waiting:
Threads enter the
Timed Waiting
state when they call methods likesleep()
orjoin()
with a timeout parameter.They wait for the specified time period or until another thread notifies them.
Terminated:
A thread completes its task and enters the
Terminated
state.This happens when the
run()
method finishes execution or an unhandled exception terminates the thread.
What is Synchronization?
Synchronization in Java refers to the mechanism that controls access to shared resources or critical sections by multiple threads. It ensures that only one thread can access the shared resource at a time, preventing concurrent access that could lead to data inconsistency or corruption.
Advantages of Synchronization:
Thread Safety: Synchronization ensures that shared resources are accessed in a mutually exclusive manner, preventing data races and maintaining data integrity.
Consistency: It helps in maintaining consistency among shared data by enforcing a strict order of access, ensuring that changes made by one thread are visible to others.
Prevents Deadlocks: Properly implemented synchronization techniques can prevent deadlock situations where two or more threads are blocked forever, waiting for each other to release resources.
Coordination: It facilitates coordination between threads, allowing them to communicate effectively and synchronize their activities based on specific conditions.
Disadvantages of Synchronization:
Overhead: Synchronization introduces overhead due to context switching and acquiring/releasing locks, which can impact performance, especially in highly concurrent applications.
Potential Deadlocks: Improper use of synchronization primitives can lead to deadlocks, where threads are stuck indefinitely waiting for resources that are held by other threads.
Complexity: Managing synchronization correctly requires careful attention to detail, as incorrect synchronization can lead to subtle bugs that are hard to detect and debug.
Reduced Parallelism: Synchronization may limit parallelism in multi-core systems, as threads may need to wait for access to shared resources even when they could otherwise execute independently.
Example:
In the example above:
The
increment()
method is synchronized to ensure that only one thread can execute it at a time, preventing race conditions when modifyingcount
.The
decrement()
method is not synchronized, which could lead to data corruption if accessed concurrently by multiple threads without proper synchronization.
What is Volatile Variable and its purpose?
In Java, a volatile variable is a type of variable that ensures visibility and atomicity guarantees when accessed or modified by multiple threads. Its primary purpose is to provide a consistent view of the variable's value across all threads, without the need for synchronization mechanisms like locks or synchronized
blocks.
Purpose of Volatile Variable:
Visibility Guarantee:
When a variable is declared as
volatile
, any write to that variable is immediately visible to other threads. This ensures that changes made by one thread are immediately reflected in other threads.
Atomicity on Writes:
Writing to a
volatile
variable is atomic. This means that operations on the variable are indivisible, and no other thread can observe an intermediate state during a write operation.
Preventing Compiler Optimizations:
Accessing a
volatile
variable prevents the compiler and the JVM from applying certain optimizations that could reorder or cache the variable's access, ensuring the variable's updated value is always read from main memory.
When to Use Volatile Variables:
Flag Variables: Use
volatile
for boolean flags or state variables that control the execution of threads across multiple cores or threads.Read-Modify-Write Operations: When performing read-modify-write operations (e.g., incrementing a counter), using
volatile
ensures atomicity without explicit synchronization.Status Flags: For variables used to signal state changes across threads, such as status updates or termination signals.
Example:
In this example:
The
flag
variable is declared asvolatile
to ensure that changes made toflag
in one thread are immediately visible to other threads.The
doWork()
method continuously checks theflag
variable's value without the need for explicit synchronization, relying on the visibility guarantee provided byvolatile
Last updated
Was this helpful?