Java Executors newWorkStealingPool() Method

The Executors class in Java provides the newWorkStealingPool() method to create a work-stealing thread pool using all available processors as its target parallelism level. This guide will cover the usage of the newWorkStealingPool() method, explain how it works, and provide concise examples to demonstrate its functionality in real-world use cases.

Introduction

The Executors.newWorkStealingPool() method creates a thread pool that maintains enough threads to support a given level of parallelism and uses multiple queues to reduce contention. Work-stealing pools are particularly useful for applications with many short-lived tasks or irregular parallel workloads.

newWorkStealingPool Method Syntax

The syntax for the newWorkStealingPool method is as follows:

public static ExecutorService newWorkStealingPool()
  • The method does not take any parameters.
  • The method returns an ExecutorService that uses a work-stealing algorithm to manage tasks.

There is also an overloaded version that allows specifying the parallelism level:

public static ExecutorService newWorkStealingPool(int parallelism)
  • The method takes a single parameter parallelism, which specifies the target parallelism level.
  • The method returns an ExecutorService that uses a work-stealing algorithm to manage tasks.

Examples

Example 1: Basic Usage with Default Parallelism

In this example, we create a work-stealing pool and submit multiple tasks to it. The pool will use the number of available processors as its target parallelism level.

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class WorkStealingPoolExample {
    public static void main(String[] args) {
        // Create a work-stealing pool
        ExecutorService executor = Executors.newWorkStealingPool();

        // Submit tasks to the executor
        for (int i = 0; i < 10; i++) {
            final int taskNumber = i + 1;
            executor.submit(() -> {
                System.out.println("Executing task " + taskNumber + " by " + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000); // Simulate task execution
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Task " + taskNumber + " completed by " + Thread.currentThread().getName());
            });
        }

        // Shutdown the executor
        executor.shutdown();
    }
}

Output:

Executing task 1 by ForkJoinPool-1-worker-1
Executing task 2 by ForkJoinPool-1-worker-2
Executing task 3 by ForkJoinPool-1-worker-3
Executing task 4 by ForkJoinPool-1-worker-4
Executing task 5 by ForkJoinPool-1-worker-5
Executing task 6 by ForkJoinPool-1-worker-6
Executing task 7 by ForkJoinPool-1-worker-7
Executing task 8 by ForkJoinPool-1-worker-8
Executing task 9 by ForkJoinPool-1-worker-9
Executing task 10 by ForkJoinPool-1-worker-10
Task 1 completed by ForkJoinPool-1-worker-1
Task 2 completed by ForkJoinPool-1-worker-2
Task 3 completed by ForkJoinPool-1-worker-3
Task 4 completed by ForkJoinPool-1-worker-4
Task 5 completed by ForkJoinPool-1-worker-5
Task 6 completed by ForkJoinPool-1-worker-6
Task 7 completed by ForkJoinPool-1-worker-7
Task 8 completed by ForkJoinPool-1-worker-8
Task 9 completed by ForkJoinPool-1-worker-9
Task 10 completed by ForkJoinPool-1-worker-10

Example 2: Specifying Parallelism Level

In this example, we create a work-stealing pool with a specified parallelism level and submit multiple tasks to it.

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CustomParallelismExample {
    public static void main(String[] args) {
        // Create a work-stealing pool with a parallelism level of 4
        ExecutorService executor = Executors.newWorkStealingPool(4);

        // Submit tasks to the executor
        for (int i = 0; i < 8; i++) {
            final int taskNumber = i + 1;
            executor.submit(() -> {
                System.out.println("Executing task " + taskNumber + " by " + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000); // Simulate task execution
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Task " + taskNumber + " completed by " + Thread.currentThread().getName());
            });
        }

        // Shutdown the executor
        executor.shutdown();
    }
}

Output:

Executing task 1 by ForkJoinPool-1-worker-1
Executing task 2 by ForkJoinPool-1-worker-2
Executing task 3 by ForkJoinPool-1-worker-3
Executing task 4 by ForkJoinPool-1-worker-4
Executing task 5 by ForkJoinPool-1-worker-1
Executing task 6 by ForkJoinPool-1-worker-2
Executing task 7 by ForkJoinPool-1-worker-3
Executing task 8 by ForkJoinPool-1-worker-4
Task 1 completed by ForkJoinPool-1-worker-1
Task 2 completed by ForkJoinPool-1-worker-2
Task 3 completed by ForkJoinPool-1-worker-3
Task 4 completed by ForkJoinPool-1-worker-4
Task 5 completed by ForkJoinPool-1-worker-1
Task 6 completed by ForkJoinPool-1-worker-2
Task 7 completed by ForkJoinPool-1-worker-3
Task 8 completed by ForkJoinPool-1-worker-4

Example 3: Handling Irregular Parallel Workloads

In this example, we use a work-stealing pool to handle tasks with irregular workloads, demonstrating its capability to balance the load efficiently.

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class IrregularWorkloadExample {
    public static void main(String[] args) {
        // Create a work-stealing pool
        ExecutorService executor = Executors.newWorkStealingPool();

        // Submit tasks with irregular workloads to the executor
        for (int i = 0; i < 10; i++) {
            final int taskNumber = i + 1;
            executor.submit(() -> {
                int sleepTime = (int) (Math.random() * 2000) + 500; // Simulate irregular workload
                System.out.println("Executing task " + taskNumber + " by " + Thread.currentThread().getName() + " (sleep " + sleepTime + "ms)");
                try {
                    Thread.sleep(sleepTime); // Simulate task execution
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Task " + taskNumber + " completed by " + Thread.currentThread().getName());
            });
        }

        // Shutdown the executor
        executor.shutdown();
    }
}

Output:

Executing task 1 by ForkJoinPool-1-worker-1 (sleep 1481ms)
Executing task 2 by ForkJoinPool-1-worker-2 (sleep 1067ms)
Executing task 3 by ForkJoinPool-1-worker-3 (sleep 1917ms)
Executing task 4 by ForkJoinPool-1-worker-4 (sleep 978ms)
Executing task 5 by ForkJoinPool-1-worker-5 (sleep 1124ms)
Executing task 6 by ForkJoinPool-1-worker-6 (sleep 1743ms)
Executing task 7 by ForkJoinPool-1-worker-7 (sleep 1703ms)
Executing task 8 by ForkJoinPool-1-worker-8 (sleep 676ms)
Executing task 9 by ForkJoinPool-1-worker-9 (sleep 907ms)
Executing task 10 by ForkJoinPool-1-worker-10 (sleep 1144ms)
Task 8 completed by ForkJoinPool-1-worker-8
Task 9 completed by ForkJoinPool-1-worker-9
Task 4 completed by ForkJoinPool-1-worker-4
Task 2 completed by ForkJoinPool-1-worker-2
Task 10 completed by ForkJoinPool-1-worker-10
Task 5 completed by ForkJoinPool-1-worker-5
Task 1 completed by ForkJoinPool-1-worker-1
Task 7 completed by ForkJoinPool-1-worker-7
Task 6 completed by ForkJoinPool-1-worker-6
Task 3 completed by ForkJoinPool-1-worker-3

Conclusion

The Executors.newWorkStealingPool() method in Java is used for creating a thread pool that uses a work-stealing algorithm to manage tasks. It is particularly useful for applications with many short-lived tasks or irregular parallel workloads, as it helps balance the load efficiently across multiple threads.

Comments