Multithreading is the ability of a CPU to execute multiple threads concurrently. Threads are lightweight processes that share the same memory space.
Threads are the smallest unit of a process that can be scheduled for execution.
class MyThread extends Thread {
public void run() {
System.out.println("Thread is running");
}
}
public class Main {
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start(); // Starts the thread
}
}
A deadlock occurs when two or more threads are waiting for each other to release resources, leading to an infinite waiting state.
- Avoid nested locks.
- Use a timeout for locks.
- Use a deadlock detection mechanism.
class Resource {
synchronized void methodA(Resource resource) {
resource.methodB();
}
synchronized void methodB() {
System.out.println("Locked");
}
}
public class Main {
public static void main(String[] args) {
Resource r1 = new Resource();
Resource r2 = new Resource();
new Thread(() -> r1.methodA(r2)).start();
new Thread(() -> r2.methodA(r1)).start();
}
}
Ensures that multiple processes or threads execute in a coordinated manner to avoid race conditions.
class Counter {
private int count = 0;
synchronized void increment() {
count++;
}
synchronized int getCount() {
return count;
}
}
public class Main {
public static void main(String[] args) {
Counter counter = new Counter();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) counter.increment();
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) counter.increment();
});
t1.start();
t2.start();
}
}
import java.util.concurrent.Semaphore;
class Resource {
private final Semaphore semaphore = new Semaphore(2);
void accessResource() {
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + " is accessing the resource.");
Thread.sleep(1000);
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Main {
public static void main(String[] args) {
Resource resource = new Resource();
for (int i = 0; i < 5; i++) {
new Thread(resource::accessResource).start();
}
}
}
Virtual memory is a memory management technique that uses disk space as an extension of RAM.
- Divides memory into fixed-size blocks called pages.
- Pages are stored in physical memory or on disk.
- Divides memory into variable-sized segments based on logical divisions like functions or data structures.
System calls are functions used by applications to interact with the operating system.
Although Java abstracts system calls, actions like file I/O, threading, and process control internally invoke system calls.
import java.io.FileWriter;
import java.io.IOException;
public class Main {
public static void main(String[] args) {
try (FileWriter writer = new FileWriter("example.txt")) {
writer.write("Hello, System Call in Java!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
- Fixed Size: Size is predefined.
- Contiguous Memory: Data stored in consecutive memory locations.
- Access Time: O(1) for accessing elements.
- Insertion/Deletion: O(n) as shifting elements is required.
- Dynamic Size: Grows or shrinks dynamically.
- Non-Contiguous Memory: Nodes are linked using pointers.
- Access Time: O(n) for accessing elements.
- Insertion/Deletion: O(1) if pointer is known.
- Use array for fast access or fixed-size collections.
- Use linked list for dynamic collections or frequent insertions/deletions.
A data structure that maps keys to values using a hash function.
- Chaining: Use linked lists to store multiple values at the same index.
- Open Addressing: Find the next available slot using techniques like linear probing.
Example: Chaining
class HashTable {
private LinkedList[] table;
public HashTable(int size) {
table = new LinkedList[size];
}
void put(int key, String value) {
int index = key % table.length;
if (table[index] == null) table[index] = new LinkedList<>();
table[index].add(new Entry(key, value));
}
}
class Entry {
int key;
String value;
Entry(int key, String value) {
this.key = key;
this.value = value;
}
}
- LIFO: Last In, First Out.
- Operations:
push(),pop(),peek().
- FIFO: First In, First Out.
- Operations:
enqueue(),dequeue().
class Stack {
private int[] stack;
private int top;
public Stack(int size) {
stack = new int[size];
top = -1;
}
void push(int value) {
if (top == stack.length - 1) return;
stack[++top] = value;
}
int pop() {
if (top == -1) return -1;
return stack[top--];
}
int peek() {
return (top == -1) ? -1 : stack[top];
}
}
- A hierarchical data structure.
- Binary Search Tree (BST): A tree where the left subtree has values less than the root, and the right subtree has values greater.
- A collection of nodes (vertices) and edges.
- DFS: Depth-First Search.
- BFS: Breadth-First Search.
class Node {
int value;
Node left, right;
Node(int value) {
this.value = value;
left = right = null;
}
}
class BST {
Node root;
void insert(int value) {
root = insertRec(root, value);
}
private Node insertRec(Node root, int value) {
if (root == null) return new Node(value);
if (value < root.value) root.left = insertRec(root.left, value);
else root.right = insertRec(root.right, value);
return root;
}
void inorder(Node root) {
if (root != null) {
inorder(root.left);
System.out.print(root.value + " ");
inorder(root.right);
}
}
}
void dfs(Node root) {
if (root == null) return;
System.out.print(root.value + " ");
dfs(root.left);
dfs(root.right);
}
void bfs(Node root) {
Queue queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
Node current = queue.poll();
System.out.print(current.value + " ");
if (current.left != null) queue.add(current.left);
if (current.right != null) queue.add(current.right);
}
}
- Purpose: Stores dynamically allocated objects.
- Lifespan: Managed by the garbage collector.
- Access: Slower due to non-contiguous memory and complex management.
- Examples: Objects, instance variables.
- Purpose: Stores method calls and local variables.
- Lifespan: Automatically deallocated when the method exits.
- Access: Faster due to LIFO structure.
- Examples: Primitive types, references to objects.
| Aspect | Stack | Heap |
|---|---|---|
| Allocation | Static | Dynamic |
| Management | Automatically deallocated | Managed by garbage collector |
| Speed | Faster | Slower |
| Use Case | Method calls, local vars | Objects, instance vars |