Java Multithreading Implementation and Synchronization Techniques
Understanding Multithreading
Multithreading enables concurrent execution of multiple threads, improving performance by leveraging hardware capabilities.
Concurrency vs Parallelism
- Parallelism: Simultaneous execution of instructions across multiple CPUs
- Concurrancy: Interleaved execution of instructions on a single CPU
Processes and Threads
- Process: A running program with independent resource allocation
- Thread: A single execution path within a process
- Single-threaded: One execution path
- Multi-threaded: Multiple execution paths
Thread Implementation Methods
1. Extending Thread Class
class CustomThread extends Thread {
@Override
public void run() {
for(int i=0; i<100; i++) {
System.out.println(i);
}
}
}
class ThreadDemo {
public static void main(String[] args) {
CustomThread t1 = new CustomThread();
CustomThread t2 = new CustomThread();
t1.start();
t2.start();
}
}
2. Implemanting Runnable Interface
class Task implements Runnable {
@Override
public void run() {
for(int i=0; i<100; i++) {
System.out.println(Thread.currentThread().getName()+ ":"+i);
}
}
}
class RunnableDemo {
public static void main(String[] args) {
Task task = new Task();
Thread t1 = new Thread(task, "Thread-A");
Thread t2 = new Thread(task, "Thread-B");
t1.start();
t2.start();
}
}
3. Using Callable Interface
class ResultTask implements Callable<String> {
@Override
public String call() throws Exception {
for(int i=0; i<100; i++) {
System.out.println("Processing " + i);
}
return "Task Completed";
}
}
class CallableDemo {
public static void main(String[] args) throws Exception {
ResultTask task = new ResultTask();
FutureTask<String> future = new FutureTask<>(task);
Thread worker = new Thread(future);
worker.start();
System.out.println(future.get());
}
}
Thread Control Methods
Thread Naming
worker.setName("Worker-Thread");
System.out.println(Thread.currentThread().getName());
Thread Sleep
Thread.sleep(1000); // 1 second pause
Thread Priority
worker.setPriority(Thread.MAX_PRIORITY); // Range: 1-10
Daemon Threads
worker.setDaemon(true); // JVM exits when only daemon threads remain
Thread Synchronization
Synchronized Block
synchronized(lockObject) {
// Critical section
}
Synchronized Method
public synchronized void criticalMethod() {
// Thread-safe code
}
ReentrantLock
Lock lock = new ReentrantLock();
lock.lock();
try {
// Critical section
} finally {
lock.unlock();
}
Producer-Consumer Pattern
Basic Implementation
class SharedBuffer {
private boolean available = false;
private int data;
public synchronized void produce(int value) {
while(available) {
wait();
}
data = value;
available = true;
notifyAll();
}
public synchronized int consume() {
while(!available) {
wait();
}
available = false;
notifyAll();
return data;
}
}
Using BlockingQueue
BlockingQueue<Integer> buffer = new ArrayBlockingQueue<>(10);
// Producer
buffer.put(item);
// Consumer
buffer.take();