How to do Asynchronous Programming With Java

  • Post last modified:December 15, 2022
  • Reading time:4 mins read


  • When we write code generally we end up writing synchronized code most of the time. 
  • But in many situations, it makes sense not to block the execution and execute the code asynchronously.
  • In this article, we will consider one use case where writing asynchronous code makes sense.

Use Case

  • Consider a user apply for a product such as a credit card or debit card from front-end UI.
  • Now once at the backend, we receive user requests, we perform n number of use cases such as validation, transformation, persist to DB and sending acknowledgment email, etc.
  • Now all of these processes don’t have to be synchronous. For example, we can send emails to customers irrespective of saving them to the database.
  • So we can execute this piece of logic asynchronously.

Product Type

  • Product type is enum that represents the types of product a company offers.
package AsyncExcercise;

public enum ProductType {


  • Let’s create a user POJO that we will receive from client.
package AsyncExcercise;

public class User {

    private int userId;
    private String name;
    private Enum productType;
    private String timeStamp;
    private String emailId;

    public User(int userId, String name, Enum productType, String timeStamp, String emailId) {
        this.userId = userId; = name;
        this.productType = productType;
        this.timeStamp = timeStamp;
        this.emailId = emailId;

    public String getEmailId() {
        return emailId;

    public void setEmailId(String emailId) {
        this.emailId = emailId;

    public String getTimeStamp() {
        return timeStamp;

    public void setTimeStamp(String timeStamp) {
        this.timeStamp = timeStamp;

    public int getUserId() {
        return userId;

    public void setUserId(int userId) {
        this.userId = userId;

    public String getName() {
        return name;

    public void setName(String name) { = name;

    public Enum getProductType() {
        return productType;

    public void setProductType(Enum productType) {
        this.productType = productType;

    public String toString() {
        return "User{" +
                "userId=" + userId +
                ", name='" + name + '\'' +
                ", productType=" + productType +
                ", timeStamp='" + timeStamp + '\'' +

Apply Logic

  • Now once the client sends us the user object, we perform various operations on it.
  • First thing we do is check if a user is valid, if it is then we proceed to execute the sendMail logic asynchronously and then saves user to database.
// submit userRequest
private static void apply(User user){
            // send thank you mail to the customer
            sendMail(user); // non blocking operation

            // save to database
            savetoDB(user); //


Send Email

  • Now, send email is implemented with CompletableFuture that takes supplier as an argument, we ran exceptionally to handle cases where we face some exceptions in send call.
  • If send call is successful then it prints success message otherwise exception is printed.
  • We are adding sleep time to see log of saveDB printed before sendMail to understand async behavior
private static void sendMail(User user){
         CompletableFuture.supplyAsync(() -> send(user))
                .exceptionally(throwable -> throwable.getMessage())

    private static String send(User user){
        try {
        } catch (Exception ex){
            throw  new RuntimeException("Thread Interrupted");
        // mail sender logic
            // send email
            return "SUCCESS ! email sent !";
        throw new RuntimeException("FAILED ! email sent failed :(");


  • Validate logic is just a mock behavior that returns true;l
   private static boolean validate(){

        // validation
        return true;

Save to DB

  • Save DB is also mock behavior to persist data into DB.
    private static void savetoDB(User user) {
        // jpa persit;
        System.out.println("persisted to db");

Client code

  • In client code we are creating two user , one has email address and other just has empty email.
    public static void main(String[] args) throws InterruptedException {
        User user = new User(1,
                new SimpleDateFormat("").format(new Date()),

        User user1 = new User(1,
                new SimpleDateFormat("").format(new Date()),



Console Log

  • As we can see email log is printed later than the db log, which means email logic is executed asynchronously.


  • In this article, we wrote asynchronous code that executes without blocking our execution and saves on performance.
  • Java provides a Completable class to implement asynchronous behavior

Bonus Tip

Leave a Reply