Async Programming in Java: Part I
Let's discuss asynchronous programming in Java and various ways to achieve it, starting with Thread, Runnable, and Callable.
Join the DZone community and get the full member experience.Join For Free
As a backend engineer, we face situations to process the data asynchronously. Today let's see how it's done in java and various way to do it.
Starting from Thread, Runnable, Callable<T>, Future<T> (and its extended ScheduledFuture<T>), CompletableFuture<T>, and of course, ExecutorService and ForkJoinPool. We will see all of them, but one by one.
The very basic yet so powerful component of Java concurrency is
Thread. The Thread of Java is actually associated with the Thread of the Operating System. The very basic way to create a
Thread is by extending it and overriding the
Starting the thread causes the
run() method to be called.
You may ask; yes, Thread has tons of other methods that can be overridden:
- In most cases, we don't want to override other methods of the thread.
- Once we extend the
Threadclass, the extending class losses its ability to extend further as Java does not support multiple inheritances.
- Each thread has its own object when we extend it, and it's not good for memory health when there are tons of Objects of the extended
Java addresses these issues with the Runnable interface. In fact, Thread has an overloaded method that takes Runnable.
Runnable is an interface that has only one method:
run(). Yes, Runnable is a functional interface, and its instance can be created with the lambda function. Yet it's an easy way to do this; for complex things, we might like to implement it. See the difference here. It's all about the requirement:
Though Runnable has a
run()method, it's not a Thread but just a Java class until it's taken control by (passed to) Thread. The starting of the thread causes the runnable object's
run()method to be called.
Cool, we learnt how to create threads with Thread as well as Runnable. But have you noticed Thread (or Runnable either),
Runnablemethod doesn't return anything?
- Also doesn't have exception handling. You have to surround your code that throws an Exception with try and catch block
Yep, Java got it solved in version 1.5, and it's Callable<V>.
Callable is a generic interface. Why? The type of the return value as the generic type. Callable is too a functional interface and
call()is the only method, a no-argument method that throws Exception and returns generic type value.
The implementing Callable is very similar to Runnable:
See here, the
callmethod processes the data and returns a value that can be collected post-execution. But is there a huge difference in invoking it? We use
ExecutorService to invoke and
Future to hold the result. Let's talk about why.
As you can see, there is no controlled behavior of creating and running the Threads (Runnable or Callable too). We may want to control the number of threads running at a time as each of them associated with OS's threads. The number of Threads we run should be lesser than the number of available CPU cores. All together, Java solves it by ExecutorService interface.
I think it's really a lot for today. Maybe in Part II, we will discuss Executors and different types of ExecutorService, and the Future<V> interface.
Opinions expressed by DZone contributors are their own.