Open In App

Structured Concurrency in Java

Last Updated : 14 May, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Structured concurrency organizes concurrent processes in a controlled way to ease concurrent execution. It prevents race situations, deadlocks, and orphaned jobs. Structured concurrency may be implemented in Java utilizing libraries, frameworks, or experimental initiatives like Project Loom. Structured concurrency concepts and techniques in Java:

  1. ExecutorService and CompletableFuture
  2. ForkJoinPool and RecursiveTask

ExecutorService and CompletableFuture

ExecutorService in java.util.concurrent manages a pool of worker threads that may perform tasks simultaneously. CompletableFuture lets you link, manage, and combine tasks. ExecutorService and CompletableFuture provide systematic concurrency management of concurrent processes.

Example:

Java




// Java Program to demonstrate structured concurrency in
// Java using the ExecutorService and CompletableFuture
// classes from the java.util.concurrent package.
import java.util.concurrent.*;
  
// Driver class
public class StructuredConcurrencyExample {
  
    // function main
    public static void main(String[] args)
        throws InterruptedException, ExecutionException
    {
        ExecutorService executor
            = Executors.newFixedThreadPool(3);
  
        CompletableFuture<Void> task1
            = CompletableFuture.runAsync(() -> {
                  System.out.println("Task 1 started");
                  // Perform task 1
              }, executor);
  
        CompletableFuture<Void> task2
            = CompletableFuture.runAsync(() -> {
                  System.out.println("Task 2 started");
                  // Perform task 2
              }, executor);
  
        CompletableFuture<Void> combinedTasks
            = CompletableFuture.allOf(task1, task2);
        // Waits for both tasks to complete
        combinedTasks.get();
  
        executor.shutdown();
    }
}


Output

Task 1 started
Task 2 started

Note: The order of the task outputs may vary because the tasks are executed concurrently, and the order in which they complete may not be the same each time.

ForkJoinPool and RecursiveTask

ForkJoinPool, another concurrency framework in the java.util.concurrent package efficiently executes divide-and-conquer algorithms and steals work. ForkJoinPool with RecursiveTask or RecursiveAction creates organized concurrent tasks.

Example:

Java




// Java program to demonstrate the use of the ForkJoinPool
// to create organized concurrent tasks.
import java.util.concurrent.*;
  
public class StructuredConcurrencyExample {
    public static void main(String[] args)
    {
        ForkJoinPool forkJoinPool = new ForkJoinPool();
  
        // Task 1
        RecursiveAction task1 = new RecursiveAction() {
            @Override protected void compute()
            {
                // Perform task 1
                System.out.println("Task 1 started");
            }
        };
  
        // Task 2
        RecursiveAction task2 = new RecursiveAction() {
            @Override protected void compute()
            {
                // Perform task 2
                System.out.println("Task 2 started");
            }
        };
  
        // Submit both tasks and then join them
        ForkJoinTask<Void> submittedTask1
            = forkJoinPool.submit(task1);
        ForkJoinTask<Void> submittedTask2
            = forkJoinPool.submit(task2);
  
        // Wait for both tasks to complete
        submittedTask1.join();
        submittedTask2.join();
  
        forkJoinPool.shutdown();
    }
}


Output

Task 1 started
Task 2 started

 Note: The order of the task outputs may vary because the tasks are executed concurrently, and the order in which they complete may not be the same each time.



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads