Java Threads
Concurrent programming and multithreading
๐งต What are Threads?
Threads allow concurrent execution of multiple parts of a program. They enable multitasking within a single application, improving performance and responsiveness.
// Simple thread creation
Thread thread = new Thread(() -> {
System.out.println("Running in thread: " + Thread.currentThread().getName());
});
thread.start();
Output:
Running in thread: Thread-0
Thread executes concurrently with main program
Thread Concepts
Thread Class
Extend Thread class
class MyThread extends Thread {
public void run() { }
}
Runnable Interface
Implement Runnable interface
class Task implements Runnable {
public void run() { }
}
Synchronization
Thread-safe operations
synchronized void method() {
// Thread-safe code
}
Thread Pool
Manage multiple threads
ExecutorService executor =
Executors.newFixedThreadPool(5);
๐น Creating Threads
Two main ways to create threads in Java:
// Method 1: Extending Thread class
class MyThread extends Thread {
private String threadName;
public MyThread(String name) {
this.threadName = name;
}
@Override
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.println(threadName + " - Count: " + i);
try {
Thread.sleep(1000); // Sleep for 1 second
} catch (InterruptedException e) {
System.out.println(threadName + " interrupted");
}
}
}
}
// Method 2: Implementing Runnable interface
class MyTask implements Runnable {
private String taskName;
public MyTask(String name) {
this.taskName = name;
}
@Override
public void run() {
for (int i = 1; i <= 3; i++) {
System.out.println(taskName + " - Step: " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
System.out.println(taskName + " interrupted");
}
}
}
}
// Usage
public class ThreadExample {
public static void main(String[] args) {
// Using Thread class
MyThread thread1 = new MyThread("Worker-1");
thread1.start();
// Using Runnable interface
Thread thread2 = new Thread(new MyTask("Task-1"));
thread2.start();
}
}
Output:
Worker-1 - Count: 1
Task-1 - Step: 1
Task-1 - Step: 2
Worker-1 - Count: 2
... (concurrent execution)
๐น Thread Synchronization
Preventing race conditions with synchronized methods:
class Counter {
private int count = 0;
// Synchronized method - thread-safe
public synchronized void increment() {
count++;
System.out.println(Thread.currentThread().getName() +
" - Count: " + count);
}
public synchronized int getCount() {
return count;
}
}
class CounterThread extends Thread {
private Counter counter;
private String threadName;
public CounterThread(Counter counter, String name) {
this.counter = counter;
this.threadName = name;
}
@Override
public void run() {
for (int i = 0; i < 5; i++) {
counter.increment();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
System.out.println(threadName + " interrupted");
}
}
}
}
// Usage
public class SynchronizationExample {
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
CounterThread t1 = new CounterThread(counter, "Thread-1");
CounterThread t2 = new CounterThread(counter, "Thread-2");
t1.start();
t2.start();
// Wait for threads to complete
t1.join();
t2.join();
System.out.println("Final count: " + counter.getCount());
}
}
Output:
Thread-1 - Count: 1
Thread-2 - Count: 2
Thread-1 - Count: 3
... (synchronized execution)
Final count: 10
๐น Thread Pool with ExecutorService
Managing multiple threads efficiently:
import java.util.concurrent.*;
class WorkerTask implements Runnable {
private int taskId;
public WorkerTask(int id) {
this.taskId = id;
}
@Override
public void run() {
System.out.println("Task " + taskId + " started by " +
Thread.currentThread().getName());
try {
// Simulate work
Thread.sleep(2000);
} catch (InterruptedException e) {
System.out.println("Task " + taskId + " interrupted");
}
System.out.println("Task " + taskId + " completed");
}
}
public class ThreadPoolExample {
public static void main(String[] args) {
// Create thread pool with 3 threads
ExecutorService executor = Executors.newFixedThreadPool(3);
// Submit 6 tasks
for (int i = 1; i <= 6; i++) {
executor.submit(new WorkerTask(i));
}
// Shutdown executor
executor.shutdown();
try {
// Wait for all tasks to complete
if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
}
System.out.println("All tasks completed");
}
}
Output:
Task 1 started by pool-1-thread-1
Task 2 started by pool-1-thread-2
Task 3 started by pool-1-thread-3
Task 1 completed
Task 4 started by pool-1-thread-1
... (managed execution)