SoFunction
Updated on 2025-04-09

Five implementation methods for converting asynchronous calls to synchronization in Java

Five implementation methods for converting asynchronous calls to synchronization in Java

Updated: February 26, 2025 16:40:32 Author: Yuan Xiaocai
This article introduces five methods to convert asynchronous calls into synchronous blocking mode: wait/notify, ReentrantLock+Condition, Future, CountDownLatch and CyclicBarrier. Each method has its own applicable scenarios and core mechanisms. You can choose the appropriate method according to specific needs. Friends who need it can refer to it.

The core difference between asynchronous and synchronization

  • Synchronous call: The caller blocks and waits for the result to return
  • Asynchronous call: The caller returns immediately and gets the results through callbacks/polling, etc.

This article focuses on how to convert asynchronous calls to synchronous blocking mode. Here are five implementation solutions:

Method 1: Use wait/notify + synchronized

Code Example

 public class ProducerConsumerExample {
     private static final int BUFFER_SIZE = 5;
     private final Object lock = new Object();
     private int[] buffer = new int[BUFFER_SIZE];
     private int count = 0;
 
     // Producer thread     public void produce() throws InterruptedException {
         int value = 0;
         while (true) {
             synchronized (lock) {
                 while (count == BUFFER_SIZE) {
                     ("The buffer is full, the producer is waiting...");
                     ();
                 }
                 buffer[count++] = value++;
                 ("Production Data: " + value + ", Number of buffers: " + count);
                 ();
             }
             (1000);
         }
     }
 
     // Consumer thread     public void consume() throws InterruptedException {
         while (true) {
             synchronized (lock) {
                 while (count == 0) {
                     ("The buffer is empty, the consumer is waiting...");
                     ();
                 }
                 int value = buffer[--count];
                 ("Consumption Data: " + value + ", Number of buffers: " + count);
                 ();
             }
             (1500);
         }
     }
 
     public static void main(String[] args) {
         ProducerConsumerExample example = new ProducerConsumerExample();
     
         // Start producer and consumer threads         new Thread(example::produce).start();
         new Thread(example::consume).start();
     }
 }

Key Points

  • Shared resource protection: ensure thread safety through synchronized(lock)

  • Conditional judgment:

    • While loop instead of if​ prevent false wakeup
    • The producer waits when the buffer is full (wait()​)
    • The buffer is empty when the consumer waits (wait()​)
  • Collaboration mechanism: wake up the waiting thread through notify() after each operation

  • Method comparison:

    • notify(): Wake up a single waiting thread
    • notifyAll(): Wake up all waiting threads (suitable for multi-producer scenarios)

Method 2: Use ReentrantLock + Condition

Code Example

 import ;
 import ;
 
 public class TestReentrantLock4 {
     static ReentrantLock lock = new ReentrantLock();
     static Condition moneyCondition = ();
     static Condition ticketCondition = ();
     static boolean haveMoney = false;
     static boolean haveTicket = false;
 
     public static void main(String[] args) throws InterruptedException {
         // Farmer 1 (waiting for money)         new Thread(() -> {
             ();
             try {
                 while (!haveMoney) {
                     ("Farmer 1 is waiting for funds...");
                     ();
                 }
                 ("Farmer 1 gets the funds and goes home!");
             } finally {
                 ();
             }
         }, "Farmer1").start();
 
         // Farmer 2 (wait for tickets)         new Thread(() -> {
             ();
             try {
                 while (!haveTicket) {
                     ("Farmer 2 is waiting for the ticket...");
                     ();
                 }
                 ("Farmer 2 gets the ticket and goes home!");
             } finally {
                 ();
             }
         }, "Farmer2").start();
 
         // Main thread simulates the issuance conditions         (1000);
         ();
         try {
             haveMoney = true;
             ();
             ("Funds have been issued!");
 
             haveTicket = true;
             ();
             ("Tickets have been issued!");
         } finally {
             ();
         }
     }
 }

Core features

  • Multi-condition support:

    • A lock object can bind multiple Conditions (such as moneyCondition/ticketCondition)
  • Accurate wake-up:

    • await(): Release the lock and wait for a specific condition
    • signal(): wake up the waiting thread that meets the condition
  • Code structure:

    • Must operate between() and finally unlock()
    • Conditional judgment Use while loop to prevent false wake-up

Method 3: Future (Callable + ExecutorService)

Code Example

 import .*;
 
 public class FutureExample {
     public static void main(String[] args) {
         ExecutorService executor = ();
 
         Future<Integer> future = (() -> {
             int sum = 0;
             for (int i = 1; i <= 100; i++) {
                 sum += i;
                 (10);
             }
             return sum;
         });
 
         ("The main thread performs other tasks...");
     
         try {
             Integer result = (2, );
             ("Calculation results: 1+2+...+100 = " + result);
         } catch (TimeoutException e) {
             ("Calculation timeout!");
             (true);
         } catch (Exception e) {
             ();
         } finally {
             ();
         }
     }
 }

Key APIs

method effect
​()​ Blocking to get results (timeout can be set)
​()​ Cancel task execution
​isDone()​ Check whether the task is completed

Execution process

  • Submit Callable tasks to thread pool
  • The main thread continues to perform other operations
  • Call()​ to block and wait for the result
  • Handle possible exceptions
  • Finally close the thread pool resource

Method 4: CountDownLatch (multi-threaded synchronization)

Code Example

 import ;
 import ;
 import ;
 
 public class CountDownLatchExample {
     private static final int RUNNERS = 5;
     private static final CountDownLatch startSignal = new CountDownLatch(1);
     private static final CountDownLatch readySignal = new CountDownLatch(RUNNERS);
 
     public static void main(String[] args) throws InterruptedException {
         ExecutorService executor = (RUNNERS);
 
         for (int i = 1; i <= RUNNERS; i++) {
             (() -> {
                 try {
                     ("athlete" + i + "Preparing...");
                     (300);
                     ();
 
                     ();
                     ("athlete" + i + "Start!");
                 
                     ((long)(() * 1000));
                     ("athlete" + i + "Get the end!");
                 } catch (InterruptedException e) {
                     ();
                 }
             });
         }
 
         ("The referee waits for the athlete to take his seat...");
         ();
         ("\nAll athletes are in place!");
 
         (1);
         ("The starting gun fires!");
         ();
 
         ();
         (5, );
         ("\nThe match is over!");
     }
 }

Application scenarios

  • Unified execution after multi-threading: if the service starts, wait for all components to be ready
  • Concurrent test control: Simulate fixed number of requests to be initiated simultaneously
  • Event-driven programming: Wait for multiple preconditions to complete

Method 5: CyclicBarrier (reusable synchronization barrier)

Code Example

 import ;
 import ;
 
 public class CyclicBarrierExample {
     private static final CyclicBarrier barrier = 
         new CyclicBarrier(3, () -> ("\n===== Entering the next stage ====="));
 
     public static void main(String[] args) {
         for (int i = 1; i <= 3; i++) {
             new Thread(new TeamMember(i)).start();
         }
     }
 
     static class TeamMember implements Runnable {
         private int id;
 
         public TeamMember(int id) {
              = id;
         }
 
         @Override
         public void run() {
             try {
                 doWork("Demand Analysis", 1000);
                 ();
             
                 doWork("Development coding", 1500);
                 ();
             
                 doWork("Test Deployment", 800);
                 ();
             } catch (Exception e) {
                 ();
             }
         }
 
         private void doWork(String phase, int baseTime) throws InterruptedException {
             int time = baseTime + (int)(() * 500);
             ("%s Complete %s(%dms)\n", 
                 ().getName(), phase, time);
             (time);
         }
     }
 }

Core features

Comparison items CountDownLatch CyclicBarrier
Reusability One-time use Repeatable trigger
Thread relationship The main thread is waiting for the child thread Child threads are waiting for each other
Typical scenarios Execute after thread initialization is completed Multi-stage task collaboration

Summary comparison table

method Applicable scenarios Core mechanism Extensibility
wait/notify Simple Producer-Consumer Model Waiting/notifying mechanism for object locks Low
ReentrantLock+Condition Requires multiple condition variables Fine condition control middle
Future Asynchronous task result acquisition Task submission and result callback high
CountDownLatch Multi-threaded waiting for a single event Counter decrement trigger mechanism middle
CyclicBarrier Multi-stage task synchronization Resettable barrier counting mechanism high

Best Practice Recommendations:

  • CountDownLatch is preferred for simple synchronization scenarios
  • Use Future​ when the result is returned
  • Recommended CyclicBarrier in multiple conditions or multi-stage scenarios
  • Avoid using outdated /notify​direct control

The above is the detailed content of five methods in Java to convert asynchronous calls to synchronization. For more information about Java asynchronous calls to synchronization, please pay attention to my other related articles!

  • Java
  • Asynchronous call
  • change
  • synchronous

Related Articles

  • Java reflection_Simple examples of changing variables and methods in private

    Below, the editor will bring you a simple example of Java reflection_changing variables and methods in private. The editor thinks it is quite good, so I will share it with you now and give you a reference. Let's take a look with the editor
    2016-06-06
  • SpringBoot implements asynchronous event-driven method

    This article mainly introduces SpringBoot's asynchronous event-driven method. The article introduces the example code in detail, which has certain reference learning value for everyone's learning or work. If you need it, please learn with the editor below.
    2021-06-06
  • Detailed explanation of the difference between deploying jars and wars in Spring Boot

    This article mainly introduces the details of the difference between Spring Boot deployment jar and war. The editor thinks it is quite good. I will share it with you now and give you a reference. Let's take a look with the editor
    2017-09-09
  • Detailed explanation of Spring FactoryLoader mechanism instance

    This article mainly introduces a detailed explanation of Spring FactoryLoader mechanism examples. The example code is introduced in this article in detail, which has certain reference value for everyone's learning or work. Friends who need it can refer to it.
    2020-03-03
  • Analysis of the principle and process of Java Synchronized lock upgrade

    This article mainly introduces the principles and processes of Synchronized lock upgrade in Java in detail. The sample code in the article is explained in detail. Interested friends can follow the editor to learn and learn together.
    2022-08-08
  • Spring Boot Integration Spring Boot Admin Monitoring

    This article mainly introduces Spring Boot integrated Spring Boot Admin monitoring. The example code is introduced in this article in detail, which has certain reference learning value for everyone's study or work. Friends who need it, please learn with the editor below.
    2020-08-08
  • Detailed introduction to easy-rules of Java rules engine

    This article mainly introduces the detailed introduction of easy-rules in the Java rule engine. The example code is introduced in this article in detail and has certain reference value. Interested friends can refer to it.
    2022-01-01
  • A tracking eye code that rotates with the mouse

    The tracking eye code that implements the java to follow the mouse
    2008-10-10
  • Detailed explanation of the tutorial on accessing the html page of Springboot

    This article mainly introduces the tutorial on Springboot's html page. This article has introduced you with pictures and texts in a very detailed way. Friends who need it can refer to it.
    2018-03-03
  • Example of springboot+vue implementing SSE server sending events

    This article introduces the use of Spring Boot and Vue to implement server sending events. The example code is introduced in this article in detail, which has certain reference learning value for everyone's learning or work. Friends who need it, please learn with the editor below.
    2025-01-01

Latest Comments