Java异步编程的方式

方式 说明 适用场景 核心机制/工具
1 多线程(Thread / Runnable 直接创建线程或使用 Runnable/Callable 实现异步任务 简单异步、底层控制 Thread, Runnable, ExecutorService
2 Future 和 Callable 提交任务并异步获取结果(阻塞式获取) 需要返回值的异步任务 ExecutorService.submit(Callable),返回 Future<T>
3 CompletableFuture (Java 8+) 强大的异步编程工具,支持链式调用、组合、回调、异常处理等 复杂异步流程编排 CompletableFuture.supplyAsync() / thenApply() / thenCompose()
4 回调(Callback) 异步完成后通过回调函数通知 事件驱动、异步IO等 自定义回调接口,常见于旧代码或某些框架
5 响应式编程(Reactive Programming) 基于数据流和变化传播的异步非阻塞模型 高并发、流式处理、前后端交互 Project Reactor(如 Mono/Flux)、RxJava
6 Java 异步 HTTP 客户端(如 HttpClient) 异步发送 HTTP 请求并处理响应 异步网络请求 HttpClient.sendAsync()(Java 11+)

1. 使用ThreadRunnableExecutorService

  • Runnable 定义 "要做什么"(异步任务的逻辑);
  • Thread 提供 "谁来做"(单个线程作为执行载体);
  • ExecutorService 解决 "如何高效地做"(通过线程池管理多个线程,优化资源利用)。
java 复制代码
private static void async1() {
    Runnable task = () -> {
        for (int i = 0; i < 6; i++) {
            System.out.println("异步任务执行中:" + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    };

    // 启动新线程,异步执行task中的run()方法
    Thread thread = new Thread(task);
    thread.start();
    try {
        // 主线程会等待thread执行完成
        thread.join();
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }

    System.out.println("主线程继续执行...");

    // 创建一个固定大小为2的线程池
    ExecutorService executor = Executors.newFixedThreadPool(2);

    // 提交第一个异步任务
    executor.submit(task);

   // 提交第二个异步任务(复用线程池中的线程)
    executor.submit(() -> {
        try {
            Thread.sleep(1000);
            System.out.println("第二个异步任务执行中");
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    });

    try {
        // 等待所有任务完成
        executor.awaitTermination(1, TimeUnit.MINUTES);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    // 关闭线程池
    executor.shutdown();
    System.out.println("线程池已关闭");
}

2. 使用FutureCallable

java 复制代码
// 自定义任务类(实现Callable接口,有返回值)
static class Task implements Callable<String> {
    private String name;
    private long delay;

    public Task(String name, long delay) {
        this.name = name;
        this.delay = delay;
    }

    @Override
    public String call() throws Exception {
        System.out.println(name + "开始执行...");
        Thread.sleep(delay); // 模拟耗时操作
        return name + "执行完成(耗时" + delay + "ms)";
    }
}

private static void async2() {
    // 1. 创建线程池(推荐根据实际需求调整核心线程数)
    ExecutorService executor = Executors.newFixedThreadPool(3); // 固定3个线程的线程池

    try {
        // 2. 提交异步任务(返回Future对象)
        Future<String> future1 = executor.submit(new Task("任务1", 2000));
        Future<Integer> future2 = executor.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                Thread.sleep(1500); // 模拟耗时操作
                return 100 + 200; // 任务结果
            }
        });

        // 3. 主线程可以做其他事情
        System.out.println("主线程执行其他操作...");

        // 4. 获取任务结果(get()方法会阻塞,直到任务完成)
        String result1 = future1.get();
        System.out.println("任务1结果:" + result1);

        Integer result2 = future2.get(3, TimeUnit.SECONDS); // 带超时的get()
        System.out.println("任务2结果:" + result2);

        // 5. 演示取消任务
        Future<String> future3 = executor.submit(new Task("任务3", 3000));
        Thread.sleep(1000); // 等待1秒后取消任务
        boolean isCancelled = future3.cancel(true); // true表示中断正在执行的任务
        System.out.println("任务3是否取消成功:" + isCancelled);
        System.out.println("任务3是否已完成:" + future3.isDone());

    } catch (InterruptedException e) {
        System.out.println("线程被中断:" + e.getMessage());
    } catch (ExecutionException e) {
        System.out.println("任务执行出错:" + e.getMessage());
    } catch (TimeoutException e) {
        System.out.println("获取结果超时:" + e.getMessage());
    } finally {
        // 6. 关闭线程池(必须执行,否则程序不会退出)
        executor.shutdown();
    }
}

3. CompletableFuture (Java 8+)

kotlin 复制代码
// 1. 简单异步任务(无返回值)
CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
    try {
        TimeUnit.SECONDS.sleep(1);
        System.out.println("任务1:异步执行(无返回值)");
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
});

// 2. 带返回值的异步任务
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
    try {
        TimeUnit.SECONDS.sleep(2);
        return "任务2:异步计算结果";
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
});

// 3. 链式操作(处理上一个任务的结果)
CompletableFuture<Integer> future3 = future2
        .thenApply(result -> {
            System.out.println("任务3:处理任务2的结果 -> " + result);
            return result.length(); // 计算字符串长度
        })
        .thenApply(length -> length * 2); // 再做一次处理

// 4. 组合两个异步任务(等待两者完成后处理结果)
CompletableFuture<String> future4 = future2.thenCombine(future3,
        (result2, result3) -> "任务4:组合结果 -> " + result2 + ",长度加倍后:" + result3);

// 5. 多任务并行执行(等待所有任务完成)
CompletableFuture<Void> allFutures = CompletableFuture.allOf(future1, future2, future3);
allFutures.thenRun(() -> System.out.println("所有任务执行完毕!"));

// 6. 异常处理
CompletableFuture<Integer> future5 = CompletableFuture.supplyAsync(() -> {
    if (true) {
        throw new RuntimeException("任务5执行出错!");
    }
    return 100;
}).exceptionally(ex -> {
    System.out.println("捕获异常:" + ex.getMessage());
    return -1; // 异常时返回默认值
});

// 等待所有任务完成(实际开发中很少用get()阻塞,更多用异步回调)
try {
    future5.get();
System.out.println("任务3的最终结果:" + future3.get());
System.out.println("任务4的组合结果:" + future4.get());
} catch (InterruptedException e) {
    throw new RuntimeException(e);
} catch (ExecutionException e) {
    throw new RuntimeException(e);
}

4. 回调

这种方式比较传统了,不推荐使用

java 复制代码
interface Callback {
    void onComplete(String result);
}

void asyncTask(Callback callback) {
    new Thread(() -> {
        try {
            Thread.sleep(1000);
            callback.onComplete("任务完成");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }).start();
}

// 调用
asyncTask(result -> {
    System.out.println("回调结果:" + result);
});

改用下面的

kotlin 复制代码
CompletableFuture.supplyAsync(() -> {
    // 异步任务
    return "任务结果";
}).thenAccept(result -> {
    // 回调处理结果(非阻塞)
    System.out.println("收到结果: " + result);
}).exceptionally(ex -> {
    // 异常处理
    ex.printStackTrace();
    return null;
});

5. 响应式编程(Reactive Programming)

java 复制代码
// 1. 创建一个简单的数据流(Mono - 单个元素)
Mono<String> mono = Mono.just("Hello Reactor")
        .map(s -> s + "!")
        .doOnNext(System.out::println);

// 2. 创建一个包含多个元素的数据流(Flux)
Flux<Integer> flux = Flux.range(1, 5)
        .map(i -> i * 2)
        .filter(i -> i > 5);

// 3. 异步处理示例
Flux<String> asyncFlux = Flux.just("任务1", "任务2", "任务3")
        .publishOn(Schedulers.boundedElastic()) // 切换到异步线程
        .map(task -> {
            // 模拟耗时操作
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            return task + " 处理完成";
        });

// 4. 组合多个数据流
Flux.combineLatest(
        flux.map(i -> "数字: " + i),
        asyncFlux,
        (numStr, taskStr) -> numStr + " - " + taskStr
).subscribe(
        result -> System.out.println("组合结果: " + result),  // 处理正常结果
        error -> System.err.println("错误: " + error.getMessage()),  // 处理错误
        () -> System.out.println("所有数据处理完成")  // 处理完成通知
);

// 等待异步操作完成
try {
    Thread.sleep(5000);
} catch (InterruptedException e) {
    throw new RuntimeException(e);
}

6. ### ​**Java 11+ 异步 HTTP 请求

适合微服务和网络请求场景

java 复制代码
// 1. 创建 HttpClient 实例
HttpClient client = HttpClient.newBuilder()
        .version(HttpClient.Version.HTTP_2)  // 使用 HTTP/2
        .connectTimeout(Duration.ofSeconds(10))  // 连接超时
        .build();

// 2. 创建 GET 请求
HttpRequest getRequest = HttpRequest.newBuilder()
        .uri(URI.create("https://httpbin.org/get"))
        .timeout(Duration.ofSeconds(10))
        .header("Accept", "application/json")
        .GET()
        .build();

// 3. 发送异步 GET 请求
CompletableFuture<HttpResponse<String>> getFuture = client.sendAsync(
        getRequest,
        HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)
);

// 处理 GET 请求结果(非阻塞方式)
getFuture.thenAccept(response -> {
    System.out.println("GET 响应状态码: " + response.statusCode());
    System.out.println("GET 响应体: " + response.body().substring(0, 100) + "..."); // 打印部分内容
}).exceptionally(e -> {
    System.err.println("GET 请求出错: " + e.getMessage());
    return null;
});

// 4. 创建 POST 请求(带表单数据)
HttpRequest postRequest = HttpRequest.newBuilder()
        .uri(URI.create("https://httpbin.org/post"))
        .timeout(Duration.ofSeconds(10))
        .header("Content-Type", "application/x-www-form-urlencoded")
        .POST(HttpRequest.BodyPublishers.ofString("name=test&age=20"))
        .build();

// 5. 发送异步 POST 请求
CompletableFuture<HttpResponse<String>> postFuture = client.sendAsync(
        postRequest,
        HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)
);

// 处理 POST 请求结果(阻塞方式获取,仅作示例)
HttpResponse<String> postResponse = null;
try {
    postResponse = postFuture.get();
} catch (InterruptedException e) {
    throw new RuntimeException(e);
} catch (ExecutionException e) {
    throw new RuntimeException(e);
}
System.out.println("\nPOST 响应状态码: " + postResponse.statusCode());
System.out.println("POST 响应体: " + postResponse.body().substring(0, 100) + "...");

// 等待所有异步操作完成
CompletableFuture.allOf(getFuture, postFuture).join();
System.out.println("\n所有请求处理完毕");

总结

方式 是否推荐 是否阻塞 适用场景 核心工具
Thread / Runnable ⚠️ 简单场景 是(需手动管理) 简单异步任务 Thread, Runnable
ExecutorService + Future ✅ 一般场景 获取结果是阻塞的 需要返回值的异步任务 ExecutorService, Future
CompletableFuture ✅✅ 推荐(Java 8+) 非阻塞 复杂异步逻辑、任务编排 CompletableFuture
回调(Callback)​ ⚠️ 老代码/事件驱动 通常是回调形式 传统异步通知 自定义接口
响应式编程(Reactor/RxJava)​ ✅ 高级场景 非阻塞 流式数据、高并发、WebFlux Mono, Flux, Observable
异步 HTTP 客户端(HttpClient)​ ✅ 网络请求 非阻塞 异步网络调用 HttpClient.sendAsync()
Kotlin 协程(与 Java 互操作)​ ✅ 简洁异步 非阻塞(挂起函数) 更优雅的异步代码 Kotlin Coroutines
相关推荐
David爱编程13 分钟前
多核 CPU 下的缓存一致性问题:隐藏的性能陷阱与解决方案
java·后端
追逐时光者33 分钟前
一款基于 .NET 开源、功能全面的微信小程序商城系统
后端·.net
绝无仅有2 小时前
Go 并发同步原语:sync.Mutex、sync.RWMutex 和 sync.Once
后端·面试·github
绝无仅有2 小时前
Go Vendor 和 Go Modules:管理和扩展依赖的最佳实践
后端·面试·github
自由的疯2 小时前
Java 实现TXT文件导入功能
java·后端·架构
现在没有牛仔了2 小时前
SpringBoot实现操作日志记录完整指南
java·spring boot·后端
小蒜学长2 小时前
基于django的梧桐山水智慧旅游平台设计与开发(代码+数据库+LW)
java·spring boot·后端·python·django·旅游
文心快码BaiduComate2 小时前
七夕,画个动态星空送给Ta
前端·后端·程序员
文心快码BaiduComate2 小时前
早期人类奴役AI实录:用Comate Zulu 10min做一款Chrome插件
前端·后端·程序员