Examples

1. Extending Thread

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

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

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

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();
    }
}    

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

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();
    }
}

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