Introduction
Multithreading allows concurrent execution of multiple parts of a program. Each part is called a thread.
What is Thread?
Thread = lightweight subprocess, smallest unit of processing.
Benefits:
- Better CPU utilization
- Concurrent operations
- Responsive applications
- Better resource sharing
Process vs Thread
| Process | Thread |
|---|---|
| Heavy weight | Light weight |
| Separate memory | Shared memory |
| Independent | Part of process |
| Expensive creation | Cheap creation |
| Communication slow | Communication fast |
Creating Threads
Method 1: Extending Thread Class
class MyThread extends Thread {
@Override
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}
public class Main {
public static void main(String[] args) {
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
t1.start(); // Start thread
t2.start();
}
}
Method 2: Implementing Runnable Interface
class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}
public class Main {
public static void main(String[] args) {
MyRunnable r = new MyRunnable();
Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
t1.start();
t2.start();
}
}
start() vs run()
// start() - creates new thread
t1.start(); // ✓ New thread created
// run() - executes in same thread
t1.run(); // ✗ No new thread, runs in main thread
Thread States
New → Runnable → Running → Terminated
↑ ↓
← Waiting/Blocked
- New: Thread created
- Runnable: ready to run
- Running: executing
- Waiting/Blocked: waiting for resource
- Terminated: finished execution
Thread Methods
getName() and setName():
Thread t = new Thread();
t.setName("MyThread");
System.out.println(t.getName());
currentThread():
Thread t = Thread.currentThread();
System.out.println("Current: " + t.getName());
sleep():
try {
Thread.sleep(1000); // Sleep 1 second
} catch (InterruptedException e) {
e.printStackTrace();
}
join():
Thread t1 = new Thread();
t1.start();
t1.join(); // Wait for t1 to complete
Simple Example
class Counter extends Thread {
String name;
Counter(String name) {
this.name = name;
}
@Override
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.println(name + ": " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Main {
public static void main(String[] args) {
Counter c1 = new Counter("Thread-1");
Counter c2 = new Counter("Thread-2");
c1.start();
c2.start();
}
}
Thread Priority
Priority range: 1 (MIN) to 10 (MAX), Default: 5 (NORM)
public class Main {
public static void main(String[] args) {
Thread t1 = new Thread();
Thread t2 = new Thread();
t1.setPriority(Thread.MIN_PRIORITY); // 1
t2.setPriority(Thread.MAX_PRIORITY); // 10
System.out.println("t1 priority: " + t1.getPriority());
System.out.println("t2 priority: " + t2.getPriority());
t1.start();
t2.start();
}
}
Lambda with Threads
public class Main {
public static void main(String[] args) {
// Lambda expression
Thread t = new Thread(() -> {
for (int i = 1; i <= 5; i++) {
System.out.println("Count: " + i);
}
});
t.start();
}
}
Multiple Threads Example
class Task implements Runnable {
String taskName;
Task(String taskName) {
this.taskName = taskName;
}
@Override
public void run() {
for (int i = 1; i <= 3; i++) {
System.out.println(taskName + " - Step " + i);
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(taskName + " completed");
}
}
public class Main {
public static void main(String[] args) {
Thread t1 = new Thread(new Task("Download"));
Thread t2 = new Thread(new Task("Upload"));
Thread t3 = new Thread(new Task("Process"));
t1.start();
t2.start();
t3.start();
}
}
Main Thread
public class Main {
public static void main(String[] args) {
Thread mainThread = Thread.currentThread();
System.out.println("Main thread: " + mainThread.getName());
System.out.println("Priority: " + mainThread.getPriority());
mainThread.setName("MyMainThread");
System.out.println("New name: " + mainThread.getName());
}
}
Thread Synchronization (Brief)
Problem: Multiple threads accessing shared resource.
class Counter {
int count = 0;
// Synchronized method
synchronized void increment() {
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();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Count: " + counter.count);
}
}
Daemon Thread
Background thread that doesn’t prevent JVM from exiting.
public class Main {
public static void main(String[] args) {
Thread t = new Thread(() -> {
while (true) {
System.out.println("Daemon running");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.setDaemon(true); // Make daemon
t.start();
System.out.println("Main ends");
// JVM exits, daemon thread stops
}
}
Complete Example: File Downloader
class FileDownloader extends Thread {
String fileName;
int size;
FileDownloader(String fileName, int size) {
this.fileName = fileName;
this.size = size;
}
@Override
public void run() {
System.out.println("Downloading " + fileName + "...");
for (int i = 0; i <= size; i += 10) {
System.out.println(fileName + ": " + i + "%");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(fileName + " downloaded!");
}
}
public class Main {
public static void main(String[] args) {
FileDownloader file1 = new FileDownloader("Image.jpg", 100);
FileDownloader file2 = new FileDownloader("Video.mp4", 100);
FileDownloader file3 = new FileDownloader("Document.pdf", 100);
file1.start();
file2.start();
file3.start();
System.out.println("All downloads started");
}
}
Thread vs Runnable
Prefer Runnable:
- Can extend other classes
- More flexible
- Better design
Use Thread:
- Simple cases
- Need to override Thread methods
Common Methods Summary
| Method | Description |
|---|---|
| start() | Start thread |
| run() | Thread code |
| sleep(ms) | Pause thread |
| join() | Wait for completion |
| getName() | Get thread name |
| setName() | Set thread name |
| getPriority() | Get priority |
| setPriority() | Set priority |
| currentThread() | Get current thread |
| isAlive() | Check if running |
Quick Reference
// Method 1: Extend Thread
class MyThread extends Thread {
public void run() {
// Code
}
}
MyThread t = new MyThread();
t.start();
// Method 2: Implement Runnable
class MyRunnable implements Runnable {
public void run() {
// Code
}
}
Thread t = new Thread(new MyRunnable());
t.start();
// Lambda
Thread t = new Thread(() -> {
// Code
});
t.start();
// Thread methods
Thread.sleep(1000);
t.join();
t.setPriority(Thread.MAX_PRIORITY);
Exam Tips
Remember:
- Thread = lightweight subprocess
- Two ways: extends Thread, implements Runnable
- start() starts thread, run() contains code
- sleep() pauses thread
- join() waits for completion
- Priority: 1-10, default 5
- Main thread always exists
- Daemon threads are background
- synchronized for thread safety
- Runnable preferred over Thread
Common Questions:
- What is multithreading?
- Process vs thread?
- How to create thread?
- Thread vs Runnable?
- start() vs run()?
- Thread lifecycle?
- Thread methods?
- Thread priority?
- What is daemon thread?
- Synchronization basics?