Java 异步线程如何让主线程先跑完再走?
引言在开发过程中,我们经常遇到需要异步处理的情况,如发送网络请求、执行耗时操作等。但有时我们希望主线程能够等待异步线程执行,以确保数据的一致性和正确性。本文将通过使用介绍一个解决方案 Java 中的 CountDownLatch 实现等待异步线程执行主线程的效果。
问题分析假设我们有一个场景,我们需要从多个接口获取数据,然后进行数据处理和显示。由于接口请求是平行的,我们需要等待所有接口请求完成后才能进行数据处理和显示。一种常见的实现方法是使用它 CountDownLatch。
CountDownLatch解决方案 简介CountDownLatch 是 Java.util.concurrent 包中提供的同步工具类用于控制多个线程之间的执行顺序。主要有两种方法:
await()
:让调用该方法的线程等待,直到计数器的值为 0。countDown()
:减少计数器的值 1。
CountDownLatch 创建指定初始值的工作原理是: CountDownLatch 对象,再调用多个线程 countDown()
减少计数器的方法 1 操作时,当计数器的值减少到 0 时,调用 await()
该方法的线程将被唤醒并继续执行。
假设我们需要从三个不同的接口中获取数据,并在所有接口请求完成后处理和显示数据。首先,我们定义了一种获取接口数据的方法:
public class DataService { public static String getDataFromApi(String apiUrl) { // 模拟发送请求并返回数据 try { Thread.sleep(1000); // 模拟耗时操作 } catch (InterruptedException e) { e.printStackTrace(); } return "Data from " + apiUrl; }}
然后我们创建一个主线程和三个异步线程并使用它 CountDownLatch 控制主线程,等待异步线程完成。代码如下:
import java.util.concurrent.CountDownLatch;public class MainThreadExample { public static void main(String[] args) { final CountDownLatch latch = new CountDownLatch(3); Thread thread1 = new Thread(() -> { String data = DataService.getDataFromApi("api1"); System.out.println(data); latch.countDown(); }); Thread thread2 = new Thread(() -> { String data = DataService.getDataFromApi("api2"); System.out.println(data); latch.countDown(); }); Thread thread3 = new Thread(() -> { String data = DataService.getDataFromApi("api3"); System.out.println(data); latch.countDown(); }); thread1.start(); thread2.start(); thread3.start(); try { latch.await(); // 等待所有异步线程完成 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("All tasks completed. Start data processing and display."); // 处理和显示数据 }}
在上述代码中,我们创建了初始值 3 的 CountDownLatch 对象 latch
,然后创建了三个异步线程 thread1
、thread2
和 thread3
。我们通过调用每个异步线程 DataService.getDataFromApi()
该方法模拟发送请求并获取数据,并输出到控制台。同时,我们在每个异步线程的末尾调用它 latch.countDown()
方法是减少计数器的值 1。
在主线程中,我们首先启动了三个异步线程,然后调用它们 latch.await()
该方法等待所有异步线程的执行。当计数器的值减少到 0 主线程将继续执行并输出提示信息 "All tasks completed. Start data processing and display."。此时,我们可以在这个位置进行数据处理和显示。
下图显示了上述示例中主线程和异步线程的执行流程图:
flowchart TD A[主线程] --> B[异步线程1] A[主线程]
