Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Monitoring Async Operation Completion in Java

Tech May 8 4

Java provides several mechanisms for executing asynchronous operations, with thread pools and concurrent utilities being the most frequently used approaches.

Using Future to Check Task Completion

The Future interface allows you to submit tasks to an ExecutorService and monitor their execution status. The isDone() method returns true once the task completes, either successfully or with an exception.

import java.util.concurrent.*;

public class TaskMonitor {
    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(2);
        
        Callable<String> work = () -> {
            TimeUnit.MILLISECONDS.sleep(2000);
            return "Operation finished!";
        };
        
        Future<String> pending = service.submit(work);
        
        try {
            while (!pending.isDone()) {
                System.out.println("Still processing...");
                Thread.sleep(500);
            }
            String outcome = pending.get();
            System.out.println("Output: " + outcome);
        } catch (InterruptedException | ExecutionException ex) {
            ex.printStackTrace();
        } finally {
            service.shutdown();
        }
    }
}

Parallel HTTP Requests in Web Applications

Asynchronous execution becomes valuable when coordinating multiple external calls. Submitting concurrent requests to different andpoints allows the application to wait for all responses without sequential blocking.

import java.util.concurrent.*;
import java.net.*;
import java.io.*;

public class ParallelHttpRequests {
    public static void main(String[] args) throws Exception {
        ExecutorService workers = Executors.newFixedThreadPool(4);
        
        Callable<String> request1 = () -> retrieve("https://api.service.com/data");
        Callable<String> request2 = () -> retrieve("https://api.service.com/status");
        
        Future<String> response1 = workers.submit(request1);
        Future<String> response2 = workers.submit(request2);
        
        System.out.println("Response 1: " + response1.get());
        System.out.println("Response 2: " + response2.get());
        
        workers.shutdown();
    }
    
    private static String retrieve(String address) throws IOException {
        HttpURLConnection connection = (HttpURLConnection) new URL(address).openConnection();
        connection.setRequestMethod("GET");
        
        BufferedReader reader = new BufferedReader(
            new InputStreamReader(connection.getInputStream())
        );
        StringBuilder data = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            data.append(line);
        }
        reader.close();
        return data.toString();
    }
}

Exception Handling in Asynchronous Operations

Exceptions thrown within async tasks do not propagate synchronous. CompletableFuture provides exceptionally() to handle failures gracefully without crashing the application.

import java.util.concurrent.*;

public class AsyncExceptionHandling {
    public static void main(String[] args) {
        CompletableFuture<String> computation = CompletableFuture.supplyAsync(() -> {
            throw new IllegalStateException("Process failure detected");
        });
        
        computation.thenAccept(result -> System.out.println("Value: " + result))
                    .exceptionally(error -> {
                        System.out.println("Error caught: " + error.getMessage());
                        return null;
                    });
        
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

Combining Results from Multiple Async Tasks

When coordinating dependent asynchronous operations, thenCombine() enables you to merge results from two concurrent tasks into a single computed value.

import java.util.concurrent.*;

public class MergingAsyncResults {
    public static void main(String[] args) {
        CompletableFuture<String> pipeline1 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            return "Phase one complete";
        });
        
        CompletableFuture<String> pipeline2 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            return "Phase two complete";
        });
        
        CompletableFuture<String> merged = pipeline1.thenCombine(pipeline2, 
            (first, second) -> first + " | " + second);
        
        merged.thenAccept(finalResult -> System.out.println("Final: " + finalResult));
        
        try {
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.