Examples
1. Extending Thread 
Thread Print numbers from 1 to 5 in a separate thread with a 1 second pause
Scenario: We are asked to create a thread that prints numbers from 1 to 5 with a 1-second pause.
package practice;
public class ThreadExamples {
    static class NumberPrinter extends Thread {
        public void run() {
            for (int i = 1; i <= 5; i++) {
                System.out.println("Thread: " + i);
                try {
                    Thread.sleep(1000); // Sleep for 1 second
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public static void main(String[] args) {
        NumberPrinter t = new NumberPrinter();
        t.start();
    }
}Simulate two independent threads performing tasks
Scenario: Create two threads representing background tasks that run in parallel.
package practice;
public class ThreadExamples {
    static class TaskA extends Thread {
        @Override
        public void run() {
            System.out.println("Task A running by " + Thread.currentThread().getName());
        }
    }
    static class TaskB extends Thread {
        @Override
        public void run() {
            System.out.println("Task B running by " + Thread.currentThread().getName());
        }
    }
    public static void main(String[] args) {
        TaskA t1 = new TaskA();
        TaskB t2 = new TaskB();
        t1.start();
        t2.start();
    }
}Add 2 numbers in a separate thread
Scenario: We are asked to create a separate thread that performs addition of 2 numbers.
package practice;
public class ThreadExamples {
    static class AdderThread extends Thread {
        private int a;
        private int b;
        public AdderThread(int a, int b) {
            this.a = a;
            this.b = b;
        }
        @Override
        public void run() {
            int sum = a + b;
            System.out.println("Sum (Thread): " + sum);
        }
    }
    public static void main(String[] args) {
        AdderThread add = new AdderThread(3,5);
        add.start();
    }
}2. Implementing Runnable 
Runnable Run multiple tasks using the same class
Scenario: We are asked to launch multiple threads with shared logic (e.g., printing thread names).
package practice;
public class ThreadExamples {
    static class MyRunnable implements Runnable {
        @Override
        public void run() {
            System.out.println("Thread " + Thread.currentThread().getName() + " is running");
        }
    }
    
    public static void main(String[] args) {
        MyRunnable instance = new MyRunnable();
        Thread t1 = new Thread(instance);
        Thread t2 = new Thread(instance);
        t1.start();
        t2.start();
    }
}Access a shared variable counter safely updated by two threads
Scenario: Print a shared counter from multiple threads safely.
package practice;
public class ThreadExamples {
    static class CounterRunnable implements Runnable {
        private int counter = 0;
        @Override
        public void run() {
            synchronized (this) {
                counter++;
                System.out.println(Thread.currentThread().getName() + " => Counter: " + counter);
            }
        }
    }
    public static void main(String[] args) {
        CounterRunnable instance = new CounterRunnable();
        Thread t1 = new Thread(instance);
        Thread t2 = new Thread(instance);
        t1.start();
        t2.start();
    }
}Add 2 numbers in a separate thread
Scenario: We are asked to create a separate thread that performs addition of 2 numbers.
package practice;
public class ThreadExamples {
    static class AdderRunnable implements Runnable {
        private int a;
        private int b;
        public AdderRunnable(int a, int b) {
            this.a = a;
            this.b = b;
        }
        public void run() {
            int sum = a + b;
            System.out.println("Sum (Runnable): " + sum);
        }
    }
    public static void main(String[] args) {
        Thread t = new Thread(new AdderRunnable(5, 10));
        t.start();
    }
}3. Implementing Callable 
Callable Compute factorial of a number and return result
Scenario: We are asked to return the factorial of a number using thread.
package practice;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class ThreadExamples {
    static class FactorialTask implements Callable<Integer> {
        private int n;
        public FactorialTask(int n) {
            this.n = n;
        }
        @Override
        public Integer call() {
            int fact = 1;
            for (int i = 1; i <= n; i++) {
                fact = fact * i;
            }
            return fact;
        }
    }
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FactorialTask task = new FactorialTask(5);
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<Integer> future = executor.submit(task);
        System.out.println("Factorial: " + future.get());
        executor.shutdown();
    }
}Add 2 numbers in a separate thread
Scenario: We are asked to create a separate thread that performs addition of 2 numbers.
package practice;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class ThreadExamples {
    static class AdderCallable implements Callable<Integer> {
        private int a;
        private int b;
        public AdderCallable(int a, int b) {
            this.a = a;
            this.b = b;
        }
        @Override
        public Integer call() {
            return a + b;
        }
    }
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<Integer> future = executor.submit(new AdderCallable(5, 10));
        System.out.println("Sum (Callable): " + future.get());
        executor.shutdown();
    }
}4. Using ExecutorService 
ExecutorService Submit 10 print tasks with a thread pool of size 3
Scenario: We are asked to submit a batch of printing tasks to a fixed thread pool.
package practice;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadExamples {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(3);
        for (int i = 1; i <= 10; i++) {
            final int taskId = i;
            executor.submit(() -> {
                System.out.println("Running Task " + taskId + " in " + Thread.currentThread().getName());
            });
        }
        executor.shutdown();
    }
}    Variable used in lambda expression should be final or effectively final
Schedule a periodic task every 2 seconds
Scenario: Run a health check every 2 seconds using scheduled thread pool.
package practice;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadExamples {
    public static void main(String[] args) {
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        Runnable task = () -> System.out.println("Health check at: " + System.currentTimeMillis());
        scheduler.scheduleAtFixedRate(task, 0, 2, TimeUnit.SECONDS);
    }
}Add 2 numbers in a separate thread
Scenario: We are asked to create a separate thread that performs addition of 2 numbers.
package practice;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadExamples {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        int a = 5;
        int b = 10;
        executor.execute(() -> {
            int sum = a + b;
            System.out.println("Sum (Executor + Runnable): " + sum);
        });
        executor.shutdown();
    }
}5. Using CompletableFuture 
CompletableFuture Asynchronously fetch user and print welcome message
Scenario: Simulate a service fetching a user and print a greeting message after it's done.
package practice;
import java.util.concurrent.CompletableFuture;
public class ThreadExamples {
    public static void main(String[] args) {
        CompletableFuture.supplyAsync(() -> "John Doe")
            .thenApply(user -> "Welcome, " + user)
            .thenAccept(System.out::println).get();
    }
}Chain two async operations with transformation
Scenario: Fetch user ID, then fetch user's orders based on the ID.
package practice;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class ThreadExamples {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture.supplyAsync(() -> "user123")
            .thenCompose(user -> CompletableFuture.supplyAsync(() -> "Orders for " + user))
            .thenAccept(System.out::println).get();
    }
}The main thread may exit immediately before the async operations complete, especially if it's in a main() method. That’s why we may not see any output without .get() — the CompletableFuture hasn’t finished when the program exits.
Combine multiple futures and wait for all
Scenario: Run two independent tasks and combine their results.
package practice;
import java.util.concurrent.CompletableFuture;
public class ThreadExamples {
    public static void main(String[] args) {
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Result 1");
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "Result 2");
        CompletableFuture.allOf(future1, future2)
            .thenRun(() -> {
                try {
                    System.out.println(future1.get());
                    System.out.println(future2.get());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
    }
}Add 2 numbers in a separate thread
Scenario: We are asked to create a separate thread that performs addition of 2 numbers.
package practice;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class ThreadExamples {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        int a = 5;
        int b = 10;
        CompletableFuture
            .supplyAsync(() -> a + b)
            .thenAccept(sum -> System.out.println("Sum (CompletableFuture): " + sum)).get();
    }
}Last updated