Explain Codes LogoExplain Codes Logo

How to asynchronously call a method in Java

java
async-programming
java-8
lambdas
Anton ShumikhinbyAnton Shumikhin·Dec 4, 2024
TLDR

Harness the power of Java's CompletableFuture for smooth asynchronous execution. When in doubt, check this handy example:

CompletableFuture.supplyAsync(() -> myMethod()).thenAccept(result -> { /* handle result like a boss */ });

This snippet of joy calls myMethod() asynchronously and processes its return value using a glorious naughty callback, while the main thread just chills out.

Void-returning methods: No gift, no worries

For functions that don't return any values, runAsync has got you covered:

CompletableFuture.runAsync(() -> myMethodThatReturnsVoid()).thenRun(() -> System.out.println("Done! Hallelujah!"));

Now, myMethodThatReturnsVoid() will run asynchronously and drop a message when it's done with the dirty work.

Shopping with supplyAsync()

When expecting a return, let supplyAsync spoil you with choices:

CompletableFuture.supplyAsync(() -> calculate() /* or order pizza 🍕 */) .thenApply(result -> process(result) /* no rush; add ketchup, if you like */) .thenAccept(contract -> System.out.println("Final deal: $" + contract));

Like Lazada, this orders a calculation, gets it processed, and delivers it at your doorstep, in an über-cool, non-blocking fashion.

Graceful exits and clean errors

CompletableFuture and FutureTask can help you step back from tasks gone rogue. Slaying dragons (exceptions) is just another day's work:

FutureTask<String> futureTask = new FutureTask<>(() -> { throw new IllegalStateException("Oops! Tripped on a banana peel 🤦‍♂️"); }); new Thread(futureTask).start(); try { futureTask.get(); // Ah! An ExecutionException. Well played. } catch (ExecutionException e) { Throwable cause = e.getCause(); // Caught ya! That's your banana peel. }

The executor army

Unleash the might of Executors to operate your dream thread pool:

ExecutorService executorService = Executors.newFixedThreadPool(10); executorService.submit(() -> myMethod()); // Yay! I just dumped a bunch of work. executorService.shutdown(); // Done for the day. Turn the lights off, JARVIS.

Efficiently getting your hands dirty with multiple tasks using a bunch of loyal threads, Executors ensure a royal, graceful exit and keeps tabs on all your tasks.

Time-bound method-calling with ScheduledExecutorService

Assign time-bound tasks confidently using ScheduledExecutorService:

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); scheduler.schedule(() -> myMethodThatStartsLate(), 5, TimeUnit.SECONDS); scheduler.shutdown();

This commanding snippet calls myMethodThatStartsLate() 5-second later, just like your weekend alarm ⏰.

Embracing Lambdas

Lambdas can really slim down your asynchronous calls, bringing out the poetry in your code. Old school Java:

new Thread(new Runnable() { @Override public void run() { myMethod(); } }).start();

Lambdas slimming it down:

new Thread(() -> myMethod()).start();

Notice how lambdas cut the flab from your code and put a spotlight on execution.

Safety first!

When exploring the wild west of asynchronous programming, never forget to synchronize threads while snatching those shared resources, or use Atomic classes to play nice and stay thread-safe:

AtomicInteger coroutineCounter = new AtomicInteger(0); CompletableFuture.runAsync(coroutineCounter::incrementAndGet);

This code stays safe and tight when incrementAndGet game is on!