**********Adv.
Java (Unit-1 & 2)**********
Advanced Object-Oriented Programming:
Inheritance and polymorphism
Inheritance
Definition: Inheritance is the mechanism in Java by which one class
(child/derived class) acquires the properties and behaviours of another
class (parent/base class).
Keyword: extends
Types: Single, Multilevel, Hierarchical (Java does not support multiple
inheritance with classes, but interfaces solve it).
Advantage: Code reusability, method overriding support, hierarchical
classification.
Example:
👉 Output:
Polymorphism
Definition: Polymorphism means "many forms". It allows one interface
to be used for different underlying forms (methods/objects).
Types:
1. Compile-time polymorphism (Method Overloading) → Same
method name with different parameters.
2. Run-time polymorphism (Method Overriding) → Same method
redefined in child class, resolved using dynamic method dispatch.
Example (Overloading + Overriding):
👉 Output:
1. Method Overloading (Compile-time Polymorphism)
Definition: When two or more methods in the same class have the
same name but differ in number/type/order of parameters.
Resolved at: Compile-time
Return type: Can be same or different (but parameter list must differ).
Keyword used: No special keyword (just multiple methods).
Example:
👉 Output:
2. Method Overriding (Run-time Polymorphism)
Definition: When a subclass provides its own implementation of a
method already defined in the parent class with the same name,
parameters, and return type.
Resolved at: Run-time (Dynamic Method Dispatch)
Rules:
o Must have same method signature.
o Cannot override final, static, or private methods.
o Access modifier must not be more restrictive.
o Achieved using inheritance.
Example:
👉 Output:
Abstraction in Java
Definition:
Abstraction is the OOP concept of hiding internal implementation details and
showing only essential features to the user.
Focus: What an object does, not how it does it.
Achieved in Java using:
1. Abstract Classes
2. Interfaces
1. Abstract Classes
Definition:
An abstract class is a class declared with the keyword abstract. It
cannot be instantiated and may contain:
o Abstract methods (without body)
o Concrete methods (with body)
Purpose: Provides partial abstraction, allowing common methods and
forcing subclasses to implement abstract methods.
Key Points:
o Declared using abstract keyword
o Can have constructors, instance variables, and concrete methods
o Subclasses must implement all abstract methods or be abstract
themselves
Example:
Output:
2. Interfaces
Definition:
An interface is a 100% abstract type (before Java 8) that contains only
abstract methods (Java 8+ allows default and static methods).
Purpose: Achieves full abstraction and multiple inheritance.
Key Points:
o Declared using interface keyword
o All methods are abstract (by default)
o A class implements the interface using implements keyword
o Supports multiple inheritance
Example:
Nested Classes in Java
Definition:
A nested class is a class defined within another class. Nested classes help
group classes logically, improve encapsulation, and make code more
readable.
Types of Nested Classes
1. Member Inner Class (Non-static inner class)
o Defined inside a class but outside any method.
o Can access all members (including private) of the outer class.
2. Static Nested Class
o Declared static inside the outer class.
o Can access static members of outer class only.
3. Local Inner Class
o Defined inside a method of the outer class.
o Scope is limited to the method.
4. Anonymous Inner Class
o Inner class without a name, used for instant implementation of
an interface or abstract class.
Examples:
1. Member Inner Class
Output:
2. Static Nested Class
Output:
3. Anonymous Inner Class (Example with Interface)
4. Local Inner Class
Generics and Type Erasure in Java
1. Generics
Definition:
Generics allow classes, interfaces, and methods to operate on a
“parameterized type”, providing type safety at compile-time.
Introduced in Java 5
Avoids ClassCastException at runtime
Advantages of Generics:
1. Type safety: Errors detected at compile-time
2. Code reusability: Single class/method works with multiple data types
3. Eliminates casting: No need for explicit casting
Syntax:
Example:
Output:
2. Type Erasure
Definition:
Type Erasure is the process by which the compiler removes all generic type
information at runtime.
Generics exist only at compile-time
Ensures backward compatibility with non-generic Java code
How it works:
1. Compiler replaces type parameters with Object (or the first bound if
bounded type).
2. Inserts type casts automatically.
Example:
1. Reflection
Definition:
Reflection is the ability of a Java program to inspect and manipulate classes,
methods, fields, and constructors at runtime.
Provides information about a class at runtime.
Useful in frameworks, IDEs, debugging, serialization, and dynamic code
execution.
Key Features:
Examine class metadata (fields, methods, constructors)
Instantiate objects dynamically
Invoke methods dynamically
Access private members (with setAccessible(true))
Example:
Output:
2. Annotations
Definition:
Annotations are metadata that provide information about the code but do
not directly affect program logic.
Introduced in Java 5
Can be built-in or custom-defined
Key Features:
Used for documentation, compile-time checking, runtime processing
Can be applied to classes, methods, variables, parameters, etc.
Accessed using Reflection
Built-in Examples:
Custom Annotation Example:
Data Structures and Algorithms in Java
Tree
A Tree is a non-linear hierarchical data structure that consists of nodes
connected by edges. It is used to represent relationships between elements,
such as a parent-child hierarchy.
Each tree has the following characteristics:
The topmost node is called the root.
Every node (except the root) has exactly one parent and zero or more
children.
Nodes that have no children are called leaf nodes.
The edges represent the connection (or relationship) between nodes.
🔹 Basic Terminology:
🔹 Example:
🔹 Common Types of Trees:
1. Binary Tree – Each node has at most two children (left and right).
2. Binary Search Tree (BST) – Left child < Parent < Right child.
3. AVL Tree – Self-balancing binary search tree.
4. Heap – Complete binary tree used for priority queues.
5. Trie – Used for storing strings (prefix trees).
6. N-ary Tree – A node can have N children.
🔹 Applications:
Hierarchical data representation (e.g., file system)
Databases and indexing (e.g., B-trees)
Expression parsing (syntax trees)
Searching and sorting (BST, heaps)
AI (decision trees)
🔹 Extended Tree Terminologies
🔹 Java Code to Build a Binary Tree
🔹 Output
🌳 Tree Traversal (BFS):
Definition:
Breadth-First Search (BFS), also called Level Order Traversal, is a tree traversal
technique where nodes are visited level by level from top to bottom and left
to right.
It uses a queue to keep track of nodes to be visited.
Steps of BFS:
1. Start from the root node and push it into a queue.
2. Repeat until the queue is empty:
o Remove (dequeue) the front node.
o Visit (process) it.
o Add its left child, then right child (if they exist) to the queue.
Example Tree:
Imp: Java Code (BFS Traversal):
Output:
🌳 BFS (Breadth-First Search) – Complexity
🌳 BFS on N-ary Tree
Definition:
BFS (Breadth-First Search) on an N-ary tree is the same as in a binary tree:
Visit nodes level by level, from left to right.
The difference: instead of 2 children (left & right), each node can have
N children.
Steps (Algorithm):
1. Start with the root node, push it into a queue.
2. While queue is not empty:
o Dequeue a node.
o Process (print) its value.
o Enqueue all its children (not just 2).
Example Tree (N=3 children max):
Java Code (BFS for N-ary Tree):
Complexity:
Time Complexity: O(n) → Each node visited once.
Space Complexity: O(n) → Queue may hold many children at once
(worst case, if root has N children).
🌳 DFS (Depth-First Search) Traversal
🔹 Definition:
Depth-First Search (DFS) is a tree (or graph) traversal technique where we
explore as deep as possible along each branch before backtracking.
It uses a stack (either explicitly or via recursion).
🔹 Types of DFS in a Binary Tree:
DFS can be performed in three standard ways depending on the order of
visiting nodes:
🔹 Example Tree
🔹 Step-by-Step (Preorder Example):
1⃣ Visit root → 1
2⃣ Move left → visit 2
3⃣ Go deeper → visit 4 (leaf)
4⃣ Backtrack → visit 5
5⃣ Go right subtree → 3 → 6 → 7
Output: 1 2 4 5 3 6 7
🔹 Java Implementation (All 3 Traversals-Recursively):
🔹 Output
🌳 Iterative Preorder Traversal
🔹 Definition:
In Preorder Traversal, nodes are visited in the order:
👉 Root → Left → Right
Normally, we use recursion, but in iterative preorder traversal, we use a Stack
data structure to simulate recursion manually.
🔹 Algorithm / Steps:
1⃣ Create an empty stack and push the root node into it.
2⃣ While the stack is not empty:
Pop the top node and print (visit) it.
Push its right child (if any).
Push its left child (if any).
#(Left is pushed after right so that left is processed first — stack = LIFO)
🔹 Example Tree
🔹 Java Code:
🔹 Complexity:
Iterative In-order Traversal
🔹 Definition:
In In-order Traversal, nodes are visited in the order:
👉 Left → Root → Right
Normally, we use recursion, but in iterative in-order traversal, we use a Stack
to simulate recursion manually.
🔹 Algorithm (Step by Step):
1. Create an empty Stack.
2. Initialize current = root.
3. While current!= null or stack is not empty:
o Go left: Push current to stack, move current = [Link]
o Visit node: If current == null, pop from stack, process the node
(print value), move to current = [Link]
4. Repeat until stack is empty and current = null.
🔹 Java Code:
🔹 Time & Space Complexity:
Time: O(n) → Each node visited once
Space: O(h) → Stack stores nodes up to the height of the tree.
Iterative Post-order Traversal
🔹 Definition:
In Post-order Traversal, nodes are visited in the order:
👉 Left → Right → Root
Normally, we use recursion, but in iterative post-order traversal, we use two
stacks (or one stack with a trick) to simulate recursion manually.
🔹 Algorithm (Using Two Stacks):
1. Create two empty stacks: stack1 and stack2.
2. Push root into stack1.
3. While stack1 is not empty:
o Pop a node from stack1 and push it into stack2.
o Push the node’s left child into stack1 (if exists).
o Push the node’s right child into stack1 (if exists).
4. Finally: Pop all nodes from stack2 and process them (print values).
🔹 Java Code (Two Stacks Method):
🔹 Time & Space Complexity:
Time: O(n) → Each node visited once
Space: O(n) → Two stacks store nodes
Graph:
🔹 Definition:
A Graph is a non-linear data structure that consists of a set of vertices (nodes)
and edges (connections) that connect pairs of vertices. It is used to represent
relationships or networks such as social connections, maps, or computer
networks and It is network of nodes.
🔹 Components:
Vertices (V): The points or nodes in the graph.
Edges (E): The links or connections between vertices.
🔹 Types of Graphs:
1. Directed Graph (Digraph): Edges have a direction (A → B).
2. Undirected Graph: Edges have no direction (A — B).
3. Weighted Graph: Each edge has a weight or cost.
4. Unweighted Graph: All edges have equal weight.
🔹 Representation Methods:
1. Adjacency Matrix: 2D array showing edge presence between vertices.
2. Adjacency List: Stores for each vertex a list of connected vertices.
🔹 Applications:
Social networks (friends/followers)
Google Maps (routes and distances)
Network routing algorithms
Recommendation systems
✅ Example:
🔹 Unidirectional (Uni-directional) Edges
The connection goes only one way — from one vertex to another.
Represented with an arrow → (A → B).
If there’s an edge from A to B, you cannot travel back from B to A
unless another edge (B → A) exists.
Found in Directed Graphs (Digraphs).
Example:
➡️ A → B → C (One-way roads, Twitter follow system)
🔹 Bidirectional Edges
The connection goes both ways — from A to B and B to A.
Represented with a line — (A — B).
Found in Undirected Graphs.
Example:
🔁 A — B — C (Friendship on Facebook, where both users are
connected)
Representation of Graph
🔹 Adjacency List Representation
Definition:
An Adjacency List is a collection of lists or maps used to represent which
vertices (nodes) are connected to each other in a graph.
Each vertex stores a list of its adjacent (connected) vertices.
It is the most space-efficient way to store sparse graphs (where edges are
much fewer than vertices²).
Structure:
Each vertex has a list of nodes directly connected to it.
Implemented using:
o ArrayList of ArrayLists, or
o HashMap<Integer, List<Integer>> for dynamic vertex labelling.
Example Graph:
Advantages:
✅ Uses less memory — O(V + E)
✅ Easy to traverse neighbours of a vertex
✅ Good for BFS, DFS, and Dijkstra’s algorithm
Java Implementation (Using ArrayList):
Graph used here (unweighted + undirected graph)
Output:
Time & Space Complexity:
🔹 Directed & Weighted Graph using Adjacency List
Definition:
A Directed Weighted Graph is a graph where:
Edges have direction (A → B is not the same as B → A)
Each edge carries a weight or cost (e.g., distance, time, or cost of
traversal).
Concept:
Each vertex stores a list of pairs → (destination, weight)
Example edge: A → B (weight = 5) means there’s a directed edge from
A to B with cost 5.
Java Implementation
Output:
🔹 Adjacency Matrix Representation
Definition:
An Adjacency Matrix is a 2D array (matrix) used to represent a graph.
If there is an edge between vertex i and vertex j, the matrix cell adj[i][j] is 1
(or the weight if weighted); otherwise 0.
Structure:
Let the number of vertices = V
Matrix size = V × V
Each row and column represent a vertex.
Works for both Directed and Undirected graphs.
Example (Undirected Graph):
For Directed Graph:
If edge A → B exists, only adj[A][B] = 1, not adj[B][A].
For Weighted Graph:
adj[i][j] = weight of the edge,
and 0 (or ∞) if no edge exists.
Java Implementation (Adjacency Matrix)
Output:
Advantages:
✅ Simple and easy to implement
✅ Quick edge lookup (O(1))
Disadvantages:
❌ High memory usage (O(V²)) — not good for sparse graphs
“Food distribution in flooded areas” — wo Flood Fill Algorithm.
💧 Problem Concept — Food Distribution in Flooded Area
Storyline / Real-life Analogy:
After heavy rain, a city’s map is divided into flooded and non-flooded areas.
Each cell in the grid can represent:
1 → Flooded area (people need help)
0 → Dry land (no one needs food)
We have a team that starts from certain locations and needs to reach all
connected flooded areas to distribute food.
The goal is to find:
How many separate flooded zones (regions) exist, or
How much area (count of cells) is affected in each region.
🧠 How It’s Based on Flood Fill Algorithm
We treat the 2D grid as an implicit graph:
Each cell → a node
Adjacent flooded cells (up, down, left, right) → connected nodes
We can use Flood Fill (DFS or BFS) to find:
Each connected flooded zone (component)
Its size or boundary
🧠 Example Input:
💻 Java Code Using Flood Fill (BFS Approach)
Output:
📦 Applications:
Counting flood-affected zones (real-world use)
Counting islands in a grid (LeetCode: “Number of Islands” problem)
Identifying connected components in an image
Virus spread simulation, fire spread, etc.
🔹 Flood Fill Algorithm on an Implicit Graph (2D Grid)
Definition:
The Flood Fill Algorithm is a graph traversal technique used to fill or mark all
connected cells starting from a given point in a 2D grid.
The grid is treated as an implicit graph, meaning we don’t create an actual
graph structure — instead, each cell and its adjacent cells implicitly form
edges.
Implicit Graph Meaning:
Each cell in the grid = a vertex
Each neighbouring cell (up, down, left, right — or 8 directions) =
connected edges
So, the grid behaves like a graph without explicitly storing it.
Example Grid:
Algorithm Idea (DFS / BFS):
1. Take input grid, starting cell (sr, sc), and new colour.
2. Store the original colour of the starting cell.
3. Use DFS or BFS to traverse all adjacent cells having the same original
colour.
4. Change each visited cell’s colour to the new colour.
5. Stop when:
o You go out of bounds
o Cell has a different colour.
Pseudocode (DFS):
Java Implementation (DFS version)
Output
HashMap:
🔹 1. Definition:
A HashMap is a part of Java’s java. util package and implements the Map
interface.
It stores key-value pairs and allows fast retrieval, insertion, and deletion.
Each key is unique.
Values can be duplicate or null.
Keys cannot be null more than once (only one null key allowed).
🔹 2. Features of HashMap:
🔹 4. Basic Operations:
a) put() — Add key-value
b) get () — Retrieve value by key
c) remove() — Delete key-value
d) containsKey() / containsValue()
e) size() / isEmpty()
🔹 5. Iterating over HashMap:
a) Using keySet()
b) Using entrySet() (Recommended)
c) Using Java 8 forEach()
🔹 6. Null Handling:
🔹 7. Important Methods:
🔹 8. HashMap Internal Working:
1. Hashing:
o HashMap uses the hash-Code() of the key to calculate the bucket
index.
2. Buckets:
o Each bucket stores entries (key-value pairs).
o Initially, buckets are LinkedList, after 8+ entries in Java 8+,
converted to Red-Black Tree for efficiency.
3. Collision Handling:
o Multiple keys may map to the same bucket → handled using
LinkedList / Tree.
4. Load Factor:
o Default 0.75 → resize occurs when 75% of buckets are filled.
5. Rehashing:
o When capacity exceeded, bucket array doubles and all entries
are rehashed.
🔹 9. Example Program — All Concepts Combined
Sample Output:
Time Complexity:
Unit-3,4
UNIT III: - Multithreading and Concurrency: Threads and
synchronization, thread communication and coordination,
concurrent collections, parallelism and performance optimization,
thread safety and deadlock prevention.
Multithreading Basics
1. CPU
• CPU (Central Processing Unit) is the main part of a computer that
performs all calculations and instructions.
• It is also called the brain of the computer.
• CPU executes instructions one by one.
2. Core
• A core is a processing unit inside the CPU.
• Earlier CPUs had 1 core; now we have multi-core CPUs (dual-core,
quad-core, etc.).
• Each core can execute instructions independently, so more cores =
more parallel work.
3. Program
• A program is a set of instructions written in a programming language.
• It is stored on disk and does nothing until we run it.
• Example: [Link], Java program file, etc.
4. Process
• A process is a program in execution.
• When a program runs, OS creates a process in memory.
• A process has:
o Its own memory space
o Resources (files, registers, etc.)
o At least one thread (main thread)
Multithreading
• Multithreading means running multiple threads at the same time
within the same process.
• It improves performance because different tasks run concurrently.
Examples:
• Playing a game → one thread for graphics, one for sound
• In Java → multiple threads run parallel inside the JVM
Explain Multitasking and Multithreading
1. Multitasking
• Multitasking means the Operating System can run multiple tasks
(programs/processes) at the same time.
• The CPU switches between tasks very quickly using time slicing, so it
looks like all tasks are running simultaneously.
• Example: Listening to music while browsing the internet and
downloading a file.
Types of Multitasking
1. Pre-emptive Multitasking:
OS decides when to switch tasks. (e.g., Windows, Linux)
2. Cooperative Multitasking:
Task voluntarily gives up control. (Old systems)
2. Multithreading
• Multithreading means running multiple threads within the same
process at the same time.
• Threads share the same memory but execute independently.
• It increases performance because different parts of the same program
can run concurrently.
Example:
A web browser uses:
• one thread for UI
• one for loading pages
• one for playing videos
Threads and Synchronization
1. Threads
• A thread is the smallest unit of execution inside a process.
• A single process can have multiple threads, and all threads share:
o Same memory
o Same code
o Same files
• Threads run independently, which improves performance and allows
tasks to be done concurrently.
Example:
In a browser:
• One thread loads the webpage
• One thread handles user input
• One thread plays audio/video
Benefits of Threads
• Faster execution
• Better CPU utilization
• Easy communication (shared memory)
• Useful for parallel programming
2. Synchronization
• When multiple threads access the same shared data, conflicts can
occur.
• Synchronization ensures that only one thread accesses the shared
resource at a time.
• It prevents:
o Race conditions
o Data inconsistency
o Unexpected results
Why Synchronization Is Needed?
When two threads modify the same data at the same time, final output may
become incorrect.
Example:
Two threads depositing money into the same bank account → wrong balance
if not synchronized.
3. Types of Synchronization
A. Mutual Exclusion (Mutex)
• Only one thread can enter the critical section at a time.
• Critical Section = part of code that accesses shared data.
B. Locks
• A thread locks a resource before using it and unlocks it after use.
C. Semaphores
• A signaling mechanism used to control access to a shared resource
among multiple threads.
D. Monitors
• High-level synchronization construct used in Java (using synchronized
keyword).
Thread Communication and Coordination
When multiple threads work together on a shared task, they need a way to
communicate and coordinate so that they run in the correct order.
Java provides three important methods inside Object class for thread
communication:
1. wait ()
• Makes a thread pause and release the lock.
• Thread waits until another thread notifies it.
2. notify ()
• Wakes up one thread waiting on the same object.
3. notify All ()
• Wakes up all waiting threads.
These methods help threads work in sequence and avoid conflicts.
Why Thread Communication is Needed?
• To avoid busy waiting
• To coordinate tasks like:
o Producer should produce only when buffer is empty
o Consumer should consume only when buffer has items
• To ensure proper data flow between threads
Simple Real-Life Analogy
• One thread is producer → puts items in a box
• Another thread is consumer → takes items from the box
• They must coordinate, otherwise:
o Producer may produce when box is full
o Consumer may consume when box is empty
Java Example Code
Thread Creation in Java
There are two important ways to create threads:
1️⃣ Extending the Thread Class
2️⃣ Implementing Runnable Interface
→Thread Methods
Problem:
Two threads increment a shared count variable.
Without synchronization → inconsistent value (race condition).
With synchronization → consistent final value.
Java Program
Use of join () Method in Java
The join () method is used when one thread wants to wait for another thread
to finish before continuing its own execution.
In simple words:
join () stops the current thread until the target thread completes.
⭐ Why join () is used?
1. To maintain proper sequence of execution
Example: Main thread should print the result only after worker threads
finish.
2. To avoid inconsistent output
Without join (), threads run randomly → unpredictable result.
3. To combine (join) the results from different threads.
→What is thread synchronization? What are different ways to make
threads? Write programs to make three child threads in each
program in different ways.
(A) What is Thread Synchronization?
Thread Synchronization is the technique used to control the access
of multiple threads to shared resources.
It ensures that only one thread executes the critical section at a
time, preventing:
• Race conditions
• Data inconsistency
• Unexpected output
Keywords used in synchronization:
• synchronized method
• synchronized block
• wait () and notify ()
• Locks and monitors
(C) Program–1: Create Three Child Threads Using Thread Class
* ExecutorService (Interview-Ready Explanation)
ExecutorService is a high-level framework in Java used to manage and control
a pool of threads efficiently.
It allows you to submit tasks, and the framework manages the threads
automatically.
In simple words:
“Instead of manually creating and starting threads, ExecutorService creates a
thread pool and reuses threads to run multiple tasks efficiently.”
Common ExecutorServices
• [Link](n) – fixed number of threads
• [Link]() – creates threads as needed
• [Link]() – only one worker thread
Interview Example Code
Concurrent Collections
Java’s traditional collections like ArrayList, HashMap, LinkedList are not
thread-safe. When multiple threads modify them simultaneously, it leads to:
• Data inconsistency
• Race conditions
• ConcurrentModificationException
To solve this, Java introduced the [Link] package, which
provides specially designed Concurrent Collections for multi-threaded
applications.
Why We Need Concurrent Collections
1. Thread safety without blocking the entire collection
2. Better performance over [Link]()
3. No ConcurrentModificationException during iteration
4. Allow simultaneous read/write operations
Types of Concurrent Collections
1. ConcurrentHashMap
• Thread-safe version of HashMap.
• Uses segmented locking (in older versions) or CAS + lock striping.
• Allows concurrent reads and partially concurrent writes.
• No ConcurrentModificationException during iteration.
Example:
2. CopyOnWriteArrayList
• Thread-safe version of ArrayList.
• Uses copy-on-write mechanism:
For every write operation, a new copy of the underlying array is
created.
• Ideal for read-heavy and write-light scenarios.
• Iterator never throws ConcurrentModificationException.
Example:
3. CopyOnWriteArraySet
• Uses CopyOnWriteArrayList internally.
• Thread-safe version of HashSet.
• Good for read-mostly operations.
4. ConcurrentLinkedQueue
• A non-blocking (lock-free) queue.
• Uses CAS (Compare-And-Swap) operations.
• Recommended for high-performance producer-consumer systems.
Example:
Parallelism and Performance Optimization in Java
🧩 1. What is Parallelism?
Parallelism means executing multiple tasks simultaneously to reduce total
execution time.
In Java, parallelism can be achieved using:
• Multithreading
• Executor Framework
• Fork/Join Framework
• Parallel Streams
• Concurrent Collections
Parallelism utilizes multiple CPU cores, whereas concurrency means handling
multiple tasks in overlapping time.
2. Why is Parallelism Important?
• Better CPU utilization
• Faster execution of independent tasks
• Efficient for CPU-bound operations
• Improves throughput in servers
📌 Types of Parallelism
🧨 3. Performance Optimization Techniques
A. Using Multithreading Efficiently
Avoid creating too many threads
Too many threads cause context switching → slower performance.
Use ExecutorService instead of new Thread().
B. Use Concurrent Collections
Faster than synchronized collections.
Examples:
• ConcurrentHashMap (lock striping)
• ConcurrentLinkedQueue (non-blocking)
• CopyOnWriteArrayList (read-heavy systems)
These reduce blocking = higher performance.
C. Reduce Lock Contention
Lock contention happens when multiple threads fight for the same lock.
Techniques:
• Use synchronized blocks only where needed
• Use ReentrantLock (gives tryLock, fairness)
• Use ReadWriteLock for read-heavy operations
• Prefer atomic variables (AtomicInteger, AtomicLong) instead of full
locking
Atomic classes use CAS (Compare-And-Swap) → lock-free + faster.
D. Immutability
Immutable objects require no synchronization.
Example: String, LocalDate, custom immutable classes.
F. Using Parallel Streams
For large data processing:
Internally uses ForkJoinPool.
When to use?
Large data
CPU-bound operations
When NOT to use?
Small data
I/O operations (not beneficial)
H. Use Caching
Caching results avoids repeated expensive operations.
Examples:
• Using ConcurrentHashMap for memoization
• LRU cache
• Spring Cache
I. Reduce Context Switching
Context switching is expensive.
Reduce by:
• Using correct thread pool size
• Using fewer but efficient threads
• Using non-blocking algorithms
THREAD SAFETY AND DEADLOCK PREVENTION
1. Thread Safety
Thread Safety means that a piece of code or object works correctly even
when accessed by multiple threads at the same time.
A thread-safe program ensures that:
• No race conditions
• No data inconsistency
• No unexpected behaviour
• Shared data is always correct and consistent
2. Causes of Thread-Unsafe Behaviour
1. Shared Mutable Data
When multiple threads modify the same variable.
2. Race Conditions
Output depends on timing of threads.
3. Improper Synchronization
Critical sections not protected.
4. Non-atomic operations
Example: count++ → read + modify + write (not atomic).
3. Techniques to Achieve Thread Safety
A. Synchronization
Synchronized Methods
Synchronized Blocks
Used to protect shared resources from simultaneous access.
B. Volatile Keyword
Ensures visibility of changes across threads.
Volatile prevents threads from using cached values.
C. Atomic Variables
Java provides lock-free thread-safe classes using CAS (Compare-And-Swap):
• AtomicInteger
• AtomicLong
• AtomicBoolean
Example:
Faster than synchronized.
D. Locks
ReentrantLock
• More control than synchronized
• TryLock()
• Timed lock
• Fair locking
E. ReadWriteLock
Improves performance in read-heavy applications.
• Multiple readers allowed
• Only one writer allowed
F. Immutable Objects
Immutable objects are naturally thread-safe.
Example:
String, LocalDate, custom immutable classes.
G. Thread-safe Collections
Java Collections that are thread-safe:
1. Vector
2. Hashtable
3. [Link]()
4. Concurrent Collections (Java 5+)
o ConcurrentHashMap
o CopyOnWriteArrayList
o ConcurrentLinkedQueue
Concurrent collections avoid locking the entire structure → excellent
performance.
1. What is Deadlock?
In Java, a deadlock occurs when two or more threads are blocked forever,
each waiting for a lock held by another thread.
This stops the program completely.
2. Why Deadlock Occurs?
Deadlock happens because of improper locking, especially when threads
acquire multiple locks in different orders.
Java deadlock occurs when all these 4 conditions happen:
1. Mutual Exclusion
A lock (monitor) can be held by only one thread at a time.
2. Hold and Wait
Thread holds one lock and waits for another lock.
3. No Preemption
A thread cannot forcibly take a lock from another thread.
4. Circular Wait
Thread A waits for lock B,
Thread B waits for lock A → circular chain.
Java Deadlock Example
t1: lock(a) → waiting for(b)
t2: lock(b) → waiting for(a)
⇒ Deadlock
3. Deadlock Avoidance in Java
Deadlock avoidance means runtime decisions are taken to avoid entering a
deadlock state.
1. Avoid Nested Locks
Never acquire more than one lock if not needed.
2. Avoid Holding Locks for Long Time
Keep synchronized block small.
3. Use Lock Timeout ([Link]())
Instead of waiting forever, thread backs off.
4. Use Concurrency Framework
Prefer ConcurrentHashMap, Semaphore, BlockingQueue instead of manual
locks.
These reduce chances of deadlock.
4. Deadlock Prevention in Java
Deadlock prevention ensures one or more deadlock conditions never occur.
1. Eliminate Circular Wait
Use fixed lock ordering.
Example:
Always acquire locks in the same order:
All threads must follow same lock sequence → no cycle → no deadlock.
2. Eliminate Hold and Wait
Thread requests all needed locks at once.
If any lock unavailable → release all and retry.
3. Use Immutable Objects
Immutable objects require no locking → zero deadlock risk.
4. Breaking No-Preemption Condition
Use [Link]() so a thread can be interrupted and
forced to release locks.
UNIT IV Networked and Distributed Java Applications: Socket
programming, networking fundamentals, client-server architecture,
remote method invocation (RMI), web services and APIs,
introduction to distributed computing.
1. What is Socket Programming?
Socket programming is a way to connect two devices (client and server) over
a network so that they can send and receive data.
A socket is an endpoint for communication between two machines.
Java provides socket support through:
• [Link] (Client)
• [Link] (Server)
Socket programming uses the TCP/IP protocol.
2. Types of Sockets
1. Stream Sockets (TCP)
• Reliable, connection-oriented
• Ensures no data loss
• Uses Socket and ServerSocket
2. Datagram Sockets (UDP)
• Fast, connectionless
• Body may be lost or duplicated
• Uses DatagramSocket and DatagramPacket
3. How Socket Communication Works (TCP)
Server-side steps
1. Create a ServerSocket
2. Wait for client request
3. Accept connection → returns a Socket
4. Communicate using input/output streams
5. Close connection
Client-side steps
1. Create a Socket and connect to server
2. Send/receive data
3. Close socket
⭐ 4. JAVA TCP SOCKET PROGRAM
⭐ 6. Applications of Socket Programming
• Chat applications
• Web servers
• File transfer
• Online games
• Distributed systems
• Email communication
⭐ 7. Advantages
• Fast and efficient communication
• Real-time data transfer
• Low latency
• Good for client–server systems
⭐ 8. Disadvantages
• Requires both devices to be online at the same time
• Harder to manage multiple clients
• Network security issues
What are Sockets? Draw and Explain Socket API. Write a Java
program (client → sends text, server → receives and prints).
1. What are Sockets?
A socket is an endpoint of a two-way communication link between two
programs running on a network.
It enables data exchange between:
• Client and Server
• Over TCP or UDP protocols
• Using IP Address + Port Number
A socket uniquely identifies a connection as:
2. Socket API Diagram
Explanation:
• Client creates Socket and connects to server’s IP & port.
• Server creates ServerSocket, and waits using .accept().
• Upon connection:
o InputStream → reads data
o OutputStream → sends data
• Both ends close the connection after communication.
→Java Program
Server Program (Server receives message)
Client Program (Client sends message)
Server:
1. Creates ServerSocket(5000)
2. Waits for client using accept()
3. Reads text from client through InputStream
4. Prints the received message
5. Closes connection
Client:
1. Connects to server using Socket("localhost", 5000)
2. Sends text using OutputStream
3. Closes connection
Socket API
The Socket API is a set of system calls (functions/classes) that allow
applications to communicate over a network using TCP or UDP. It provides all
the operations required to create, connect, send, receive, and close network
connections.
The Socket API is available in almost all programming languages, including
Java (Socket, ServerSocket), C (socket(), bind(), etc.).
Main Components of the Socket API
→Networking Fundamentals
Computer networking refers to connecting two or more computers so that
they can share data, resources, and services. A network works using a set of
well-defined concepts:
(a) IP Address
An IP address uniquely identifies a device on a network.
Types:
• IPv4 – 32-bit, e.g., [Link]
• IPv6 – 128-bit, e.g., FE80::1
(b) Port Number
A port identifies a specific application or process on a device.
Example:
• HTTP → 80
• HTTPS → 443
• Custom server programs → any free port (e.g., 5000)
(c) Protocol
A protocol defines rules for communication.
Two major transport protocols:
• TCP (Transmission Control Protocol)
o Connection-oriented
o Reliable, ordered delivery
o Used for chat apps, file transfer, browsers
• UDP (User Datagram Protocol)
o Connectionless
o Faster but unreliable
o Used for games, streaming, DNS
(d) DNS (Domain Name System)
Converts domain names ([Link]) to IP addresses.
(e) MAC Address
Permanent hardware address of a network card.
(f) Router, Switch, Hub
• Router: Connects different networks, forwards packets.
• Switch: Connects devices within the same LAN.
• Hub: Broadcasts data to all devices (old technology).
2. Client–Server Architecture
Client–Server is a distributed application model where the client sends a
request and the server processes it and sends a response.
Key Features
1. Two roles:
o Client: User-side application that initiates communication.
o Server: Provides services, resources, or processing.
2. Communication Model:
o Uses TCP sockets for reliable communication.
o Client always initiates the connection.
3. Centralized Control:
Server stores data and manages operations.
4. Multi-client Support:
A server can handle many clients using threads.
→Client–Server Architecture Diagram
4. Client–Server Architecture in Java
Java provides Socket API to implement networking.
⭐ Important Java Classes
• Socket – Used by client to connect to server.
• ServerSocket – Used by server to listen for requests.
• InputStream / OutputStream – For reading/writing data.
5. Advantages of Client–Server Architecture
• Centralized data and control
• Easy maintenance
• Supports multiple clients
• Scalable
• Secure communication possible
6. Applications
• Chat applications
• Web servers and browsers
• Banking systems
• Online games
• File transfer systems
→Remote method invocation (RMI)
Remote Method Invocation (RMI) is a Java mechanism that allows an object
running on one JVM (client) to invoke methods of an object running on
another JVM (server).
It supports distributed object communication and makes remote calls appear
like local method calls.
Key Features
• Allows object-to-object communication over a network.
• Provides transparency (remote call looks like local call).
• Uses stubs (client proxy) and skeletons (server handler).
• Uses TCP/IP underneath.
• Very useful for client-server distributed systems.
→Steps to Create an RMI Application
Step 1: Create a Remote Interface
Define methods that can be called remotely.
Interface must extend [Link].
Step 2: Implement the Remote Interface
Create the class that provides actual implementation and extends
UnicastRemoteObject.
Step 3: Create and Register the Server
• Create remote object
• Bind it to RMI Registry using [Link]()
Step 4: Create the Client Application
• Lookup the remote object from registry
• Invoke remote methods
Step 5: Start RMI Registry
Use:
Step 6: Run Server → then Client
→RMI Program
(a) Remote Interface — [Link]
(b) Remote Implementation — [Link]
(c) Server Program — [Link]
(d) Client Program — [Link]
6. Advantages of RMI
• Pure Java solution for distributed systems
• Simplifies remote communication
• Automatic serialization of objects
• Secure and platform-independent
RMI Architecture Diagram
Web Services and APIs
1. What Are Web Services?
A Web Service is a software component that allows two applications to
communicate over a network (mostly HTTP). It enables interoperability,
meaning systems built in different languages (Java, Python, .NET, PHP) can
communicate.
Web services expose functionalities over the internet using standard
protocols (HTTP, XML, JSON, SOAP).
In short:
Web services allow machine-to-machine communication using web
protocols.
2. Types of Web Services
(A) SOAP Web Services
• Use SOAP (Simple Object Access Protocol)
• Data format: XML only
• Highly Secure (WS-Security)
• Strict rules and standards
• Used in banking, telecom, enterprise systems
• In Java used with JAX-WS
(B) RESTful Web Services
• Based on REST (Representational State Transfer)
• Data format: JSON, XML, Text, HTML
• Lightweight and Fast
• Uses HTTP methods: GET, POST, PUT, DELETE
• Used by modern apps, mobile apps, microservices
• In Java used with JAX-RS (Jersey) or Spring Boot
⭐ 3. What is an API?
API (Application Programming Interface) is a set of rules and endpoints that
allow one application to access features or data of another application.
All REST Web Services are APIs, but not all APIs are web services.
Example:
• Java API
• JDBC API
• Servlet API
• REST API (Web API)
4. REST API in Java
Create a REST API using Spring Boot
→@RestController → marks class as REST API
→@GetMapping → handles HTTP GET request
→Returns JSON/String response
7. Advantages of Web Services
• Platform independent
• Language independent
• Loose coupling
• Scalability
• Reusability
• Interoperability
• Supports distributed systems
Introduction to Distributed Computing
Distributed Computing is a computing model where a task or application is
executed across multiple computers (nodes/machines) that work together as
a single system. These computers communicate over a network to share data,
resources, and workloads.
In a distributed system, each machine has its own CPU, memory, and storage,
but they collaborate to solve a common problem. The user experiences the
system as one combined computer, even though it is physically distributed.
Key Features of Distributed Computing
1. Multiple Independent Nodes – Each node works independently but
cooperates to complete tasks.
2. Resource Sharing – Hardware, data, files, and processing power are
shared across systems.
3. Scalability – New nodes can be added easily to increase performance.
4. Fault Tolerance – If one node fails, others can continue working.
5. Concurrency – Many processes run simultaneously on different
machines.
Examples of Distributed Systems
• Google Search Engine
• Cloud Computing (AWS, Azure)
• Distributed Databases (Hadoop, Cassandra)
• Online banking systems
• Microservices architecture
Deadlock Example Program in Java
How the Above Program Causes Deadlock
• Thread 1 locks A and waits for B
• Thread 2 locks B and waits for A
• Both threads wait forever → Deadlock occurs
• Program never finishes execution