文章目录
推荐阅读:
【01】Netty从0到1系列之I/O模型
【02】Netty从0到1系列之NIO
【03】Netty从0到1系列之Selector
【04】Netty从0到1系列之Channel
【05】Netty从0到1系列之Buffer(上)
【06】Netty从0到1系列之Buffer(下)
【07】Netty从0到1系列之零拷贝技术
【08】Netty从0到1系列之整体架构、入门程序
【09】Netty从0到1系列之EventLoop
【10】Netty从0到1系列之EventLoopGroup
一、Future
Future和Promise说明:
这两个接口都是处理【异步请求】的接口.这里的Future是指netty
当中自己定义的future
接口. io.netty.util.concurrent.Future
, Promise
是对netty future
接口进行的扩展.
jdk future
只能同步等待任务结束【成功、或者失败】才能得到结果.netty future
可以同步等待任务结束得到结果,也可以异步方式得到结果,但都要等任务结束.netty promise
不仅有netty future
的功能, 而且脱离了任务独立存在,只作为两个线程间传递结果的容器
1.1 Netty的Future是啥?
Netty Future 是 Netty 异步编程模型的核心组件,它代表一个尚未完成的异步操作的结果。与 JDK 自带的 java.util.concurrent.Future
相比,Netty Future 提供了更强大、更灵活的功能,特别是添加了监听器机制,使得异步操作的结果处理更加优雅和高效。
Netty 的 Future
体系是其高性能异步非阻塞网络编程的核心基石。它基于 Java 原生 Future
接口,进行了深度扩展和优化,构建了一套高效、灵活、线程安全的异步结果通知机制。
Netty Future 的核心特性:
- 异步结果表示:代表一个尚未完成的异步操作的结果
- 状态查询:可以检查操作是否完成、成功或失败
- 完成通知:支持添加监听器在操作完成时接收回调
- 阻塞等待:支持同步等待操作完成(可选超时)
- 链式操作:支持将多个异步操作组合成链式调用
1.2 Future 的继承体系与核心方法
Netty 的 Future 体系比 JDK 更加丰富和灵活:
io.netty.util.concurrent.Future<V>
-> ChannelFuture (扩展了Channel相关的功能)
-> ChannelPromise (可写的ChannelFuture)
io.netty.util.concurrent.Promise<V>
-> DefaultPromise (主要实现)
JDK提供的Future接口
public interface Future<V> {
// ....
}
- Future接口「FutureTask是其实现类」,定义了操作「异步任务执行的一些方法」,如获取异步任务的执行结果,取消执行任务,判断任务是否被取消,判断任务是否执行完毕.
- 如主线程让一个子线程去执行任务,子线程在执行过程中可能比较耗时,启动子线程开始执行任务后, 主线程去做其他事情了,忙其它事情或者先执行完, 过了一会才去获取子任务的执行结果或者变更的任务状态.
Future可以为主线程开启一个分支任务,专门为主线程处理耗时任务和复杂的业务.
- 异步任务必须满足三个条件:
- 线程
- 有返回值
- 异步处理
RunnableFuture
, 实现了两个接口Runnable
和Future
,也就是这个接口支持异步操作,这个是由Future
接口特性决定的.同时也可以通过Thread
类的构造方法,传入一个RunnableFuture
的接口类型的参数,用来启动线程.
public Thread(RunnableFuture<> r)
现在差一个线程的返回值, Callable
接口,实现线程的第三种方式.
@FunctionalInterface
public interface Callable<V> {
V call() throws Exception;
}
FutureTask是RunnableFuture的实现类.
public class FutureTask<V> implements RunnableFuture<V> {}
通过此类可以启动线程, 并且该线程支持异步操作.通过分析,它的构造方法如下所示:
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
结论
:
可以通过
FutureTask
完成异步任务.
public class JdkFutureTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 创建FutureTask
FutureTask<String> futureTask = new FutureTask<>(() -> {
try {
// 等待3s钟
TimeUnit.MILLISECONDS.sleep(3000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println( "[" + Thread.currentThread().getName() + "]" + " --- \t\t: " + "jdk future test running!");
return "JDK Future";
});
new Thread(futureTask).start();
// 这里阻塞住, 等待futureTask执行完毕, 获取返回值.
System.out.println( "[" + Thread.currentThread().getName() + "]" + " --- \t\t: " + "获取FutureTask的返回值: " + futureTask.get());
// 主线程会阻塞住
System.out.println( "[" + Thread.currentThread().getName() + "]" + " --- \t\t: " + "jdk future test start!");
}
}
java.util.concurrentFuture.Future
优点与缺点:
优点:
future结合线程池异步多线程任务配合, 能显著提高程序的执行效率.
同步方式执行任务
public class SyncTaskTest {
public static void main(String[] args) {
long start = System.currentTimeMillis();
try {
System.out.println("[" + Thread.currentThread().getName() + "]" + " --- \t\t: " + "执行任务一, 耗时4s~~~");
TimeUnit.SECONDS.sleep(4);
} catch (Exception e) {
e.printStackTrace();
}
try {
System.out.println("[" + Thread.currentThread().getName() + "]" + " --- \t\t: " + "执行任务二, 耗时4s~~~");
TimeUnit.SECONDS.sleep(4);
} catch (Exception e) {
e.printStackTrace();
}
try {
System.out.println("[" + Thread.currentThread().getName() + "]" + " --- \t\t: " + "执行任务三, 耗时4s~~~");
TimeUnit.SECONDS.sleep(3);
} catch (Exception e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println(Thread.currentThread().getName() + " ----- " + "代码执行共耗时: " + (end - start) + " 毫秒");
}
}
FutureTask + 线程池
执行任务:
package com.rj.demo01;
import java.util.concurrent.*;
/**
* @author laoren
*/
public class JdkFutureExecutorServiceAsyncTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
long start = System.currentTimeMillis();
FutureTask<String> f1 = new FutureTask<>(() -> {
System.out.println("[" + Thread.currentThread().getName() + "]" + " --- \t\t: " + "任务一执行: 耗时4s");
try {
TimeUnit.SECONDS.sleep(4);
} catch (Exception e) {
e.printStackTrace();
}
return "First Task!";
});
FutureTask<String> f2 = new FutureTask<>(() -> {
System.out.println("[" + Thread.currentThread().getName() + "]" + " --- \t\t: " + "任务一执行: 耗时4s");
try {
TimeUnit.SECONDS.sleep(4);
} catch (Exception e) {
e.printStackTrace();
}
return "First Task!";
});
FutureTask<String> f3 = new FutureTask<>(() -> {
System.out.println("[" + Thread.currentThread().getName() + "]" + " --- \t\t: " + "任务一执行: 耗时3s");
try {
TimeUnit.SECONDS.sleep(3);
} catch (Exception e) {
e.printStackTrace();
}
return "First Task!";
});
ExecutorService executorService = Executors.newFixedThreadPool(3);
executorService.submit(f1); // 提交任务
executorService.submit(f2);
executorService.submit(f3);
executorService.shutdown();
// get方法会阻塞住主线程
String s = f1.get();
long end = System.currentTimeMillis();
System.out.println(Thread.currentThread().getName() + " ----- " + "代码执行共耗时: " + (end - start) + " 毫秒");
}
}
特别说明: get方法在获取值的时候,会发生阻塞;
- 如果把
get
方法放在主线程的后边,则不会有太大影响.- 如果把
get
方法放在主线程任务之前
,此时get
方法会阻塞主线程执行.get方法容易发生阻塞,一般建议放在程序的最后边,阻塞的含义就是必须等待计算结果返回,否则代码不会继续向下执行.
get方法可以指定具体的待时间,在这个时间这内如果有返回值,则可以正常获取,如果没有返回值,则拉倒.
如何解决
get
获取值的时候,阻塞主线程
- 将
get
放到最后边.- 使用
isDone
方法进行轮询判断,但是可能会导致cpu空转,浪费cpu性能
while (true){
if(task.isDone()){
System.out.println(Thread.currentThread().getName() + " ----- " + task.get());
}else{
try {
TimeUnit.MILLISECONDS.sleep(500);
}catch (Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " ----- " + "正在努力处理.....");
}
}
submit和execute
提交任务的区别:
返回值
execute(Runnable command)
:无返回值。它只是简单地将任务提交给线程池执行,无法得知任务的执行状态和结果。- submit(Callable<T> task) 或者submit(Callable<T> task, T result): 【有返回值】,
- 对于
submit(Callable<T> task)
,它返回一个Future<T>
对象,可以通过这个对象来获取任务的执行结果或者检查任务是否完成、是否被取消等状态。- 对于
submit(Runnable task, T result)
,它也返回一个Future<T>
对象,当任务执行完成后,可以通过这个Future
对象获取指定的结果result
。异常处理
execute(Runnable command)
:如果任务在执行过程中抛出异常,那么这个异常会被线程池内部捕获并处理,通常情况下,调用者无法直接获取到这个异常信息(除非通过一些额外的机制,如在任务中设置全局异常处理器)。submit(Callable<T> task)
或submit(Runnable task, T result)
:如果任务在执行过程中抛出异常,这个异常会被封装在Future
对象中,调用者可以在调用Future.get()
方法时获取到这个异常,以便进行进一步的处理。使用场景
如果只需要简单地提交一个任务让线程池执行,并且不关心任务的执行结果和状态,也不需要处理任务执行过程中可能抛出的异常,那么可以使用
execute()
方法。ExecutorService executorService = Executors.newFixedThreadPool(10); executorService.execute(() -> { // 执行一些任务 });
如果需要获取任务的执行结果,或者需要检查任务的执行状态、处理任务执行过程中可能抛出的异常,那么应该使用
submit()
方法。例如:ExecutorService executorService = Executors.newFixedThreadPool(10); Future<Integer> future = executorService.submit(() -> { // 执行一些任务并返回结果 return 42; }); try { Integer result = future.get(); System.out.println("任务结果:" + result); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); }
总之,submit()
方法提供了更多的功能和灵活性,而execute()
方法则更加简单直接。在实际使用中,可以根据具体的需求选择合适的方法来提交任务。
jdk提供的Future缺点总结
- 对于结果的获取不友好
- 只能通过阻塞或者轮询的方式来获取结果.
Netty中封装的Future接口
public interface Future<V> extends java.util.concurrent.Future<V> {
}
为了更好地理解 Netty Future 的状态转换和与 JDK Future 的区别,请看下面的对比图:
Netty Future全景图
🌟 核心思想:
- “不要调用我,我会调用你” —— 回调驱动的异步编程模型。
1.3 Future 与异步操作的关系
在 Netty 中,几乎所有的 I/O 操作都是异步的,这些操作会立即返回一个 Future 对象:
1.4 Netty Future 与Java Future对比
特性 | Java Future | Netty Future |
---|---|---|
获取结果 | get() / get(timeout) | ✅ 支持 |
监听完成 | ❌ 不支持 | ✅ addListener() |
可写性 | ❌ 只读 | ✅ Promise 可写 |
线程安全 | 部分 | ✅ 完全线程安全 |
取消操作 | ✅ cancel() | ✅ 支持 |
异常获取 | ✅ | ✅ cause() |
链式调用 | ❌ | ✅ 支持 |
✅ Netty Future 的优势:
- 更适合高并发、低延迟的网络编程场景。
1.5 Future的核心操作
Netty 的 Future 提供了丰富的方法来检查状态、获取结果和处理完成事件。
1.5.1 状态检查方法
方法 | 描述 |
---|---|
isDone() | 判断操作是否已完成(无论成功、失败或取消) |
isSuccess() | 判断操作是否成功完成 |
isCancelled() | 判断操作是否被取消 |
cause() | 获取操作失败的原因,成功或未完成时返回 null |
1.5.2 同步等待方法
Future 提供了多种同步等待操作完成的方法:
方法 | 描述 |
---|---|
sync() | 阻塞等待操作完成,操作失败时抛出异常 |
syncUninterruptibly() | 类似sync() ,但不响应中断 |
await() | 阻塞等待操作完成,不抛出操作失败的异常 |
await(long timeout, TimeUnit unit) | 带超时的await() |
awaitUninterruptibly() | 不响应中断的await() |
awaitUninterruptibly(long timeout, TimeUnit unit) | 带超时且不响应中断的await() |
1.6 Netty Future 的核心接口与实现
1.6.1 io.netty.util.concurrent.Future<V>
Netty 的 Future 接口扩展了 java.util.concurrent.Future<V>
,并添加了关键能力:
public interface Future<V> extends java.util.concurrent.Future<V>, Comparable<Future<V>> {
// 是否成功
boolean isSuccess();
// 是否可取消
boolean isCancellable();
// 获取失败原因
Throwable cause();
// 添加监听器(核心!)
Future<V> addListener(GenericFutureListener<? extends Future<? super V>> listener);
// 阻塞等待完成
Future<V> await() throws InterruptedException;
Future<V> awaitUninterruptibly();
// 同步等待(阻塞直到成功)
Future<V> sync() throws InterruptedException;
Future<V> syncUninterruptibly();
}
1.6.2 io.netty.util.concurrent.Promise<V>
Promise
是可写的 Future
,代表一个可以被设置结果的“承诺”。
public interface Promise<V> extends Future<V> {
// 设置成功
Promise<V> setSuccess(V result);
// 尝试设置成功
boolean trySuccess(V result);
// 设置失败
Promise<V> setFailure(Throwable cause);
// 尝试设置失败
boolean tryFailure(Throwable cause);
// 标记为不可取消
boolean setUncancellable();
}
🔑 关键区别:
- Future:只读,只能查询状态
- Promise:可写,可以设置成功/失败
1.7 Netty Future使用示例
1.7.1 基础Future使用【模拟异步计算】
import io.netty.util.concurrent.*;
import java.util.concurrent.TimeUnit;
/**
* 演示 Netty Future 的基本用法
*/
public class NettyFutureBasicExample {
public static void main(String[] args) throws Exception {
// 创建 EventExecutor(类似线程池)
EventExecutorGroup group = new DefaultEventExecutorGroup(2);
try {
// 模拟一个异步任务
Future<String> future = asyncCompute(group.next());
// 添加监听器(推荐方式)
future.addListener((GenericFutureListener<Future<String>>) f -> {
if (f.isSuccess()) {
System.out.println("✅ 计算成功: " + f.get());
} else {
System.err.println("❌ 计算失败: " + f.cause().getMessage());
}
});
// 方式2:阻塞等待
// String result = future.sync().get();
// System.out.println("结果: " + result);
// 等待完成
future.await(5, TimeUnit.SECONDS);
} finally {
group.shutdownGracefully();
}
}
// 模拟异步计算
private static Future<String> asyncCompute(EventExecutor executor) {
DefaultPromise<String> promise = new DefaultPromise<>(executor);
executor.execute(() -> {
try {
Thread.sleep(1000); // 模拟耗时操作
if (Math.random() > 0.3) {
promise.setSuccess("Hello Netty Future!");
} else {
promise.setFailure(new RuntimeException("计算失败"));
}
} catch (Exception e) {
promise.setFailure(e);
}
});
return promise;
}
}
基础使用Future示例
import io.netty.util.concurrent.DefaultEventExecutor;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
public class BasicFutureExample {
public static void main(String[] args) throws Exception {
// 创建事件执行器
EventExecutor executor = new DefaultEventExecutor();
// 提交异步任务,返回Future
Future<Integer> future = executor.submit(() -> {
System.out.println("开始执行异步任务...");
// 模拟耗时操作
Thread.sleep(2000);
System.out.println("异步任务完成");
return 42; // 返回结果
});
System.out.println("任务已提交,是否完成: " + future.isDone());
// 1. 同步阻塞等待结果
// Integer result = future.get(); // 无限期等待
Integer result = future.get(3, TimeUnit.SECONDS); // 带超时等待
System.out.println("同步获取结果: " + result);
// 2. 异步回调方式(推荐)
Future<Integer> future2 = executor.submit(() -> {
Thread.sleep(1000);
return 100;
});
future2.addListener(f -> {
if (f.isSuccess()) {
Integer result2 = (Integer) f.getNow();
System.out.println("异步获取结果: " + result2);
} else {
System.err.println("任务失败: " + f.cause().getMessage());
}
});
// 等待异步任务完成
Thread.sleep(1500);
executor.shutdownGracefully();
}
}
1.7.2 Netty Future同步等待
package cn.tcmeta.future;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.util.concurrent.Future;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
public class FutureSyncExample {
public static void main(String[] args) {
EventLoopGroup group = new NioEventLoopGroup(1);
EventLoop eventLoop = group.next();
try {
// 提交一个耗时任务
Future<String> future = eventLoop.submit(() -> {
System.out.println("任务开始执行,将耗时3秒");
TimeUnit.SECONDS.sleep(3);
return "任务完成";
});
// 示例1: 使用await()等待
System.out.println("使用await()等待...");
try {
// 等待最多5秒
boolean completed = future.await(5, TimeUnit.SECONDS);
if (completed) {
System.out.println("await() - 操作完成,结果: " +
(future.isSuccess() ? future.get() : "失败"));
} else {
System.out.println("await() - 操作超时");
}
} catch (InterruptedException e) {
System.out.println("await() - 被中断");
Thread.currentThread().interrupt();
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
// 提交第二个任务
Future<Object> future2 = eventLoop.submit(() -> {
System.out.println("第二个任务开始执行,将耗时2秒");
TimeUnit.SECONDS.sleep(2);
// 模拟失败
throw new RuntimeException("故意抛出的异常");
});
// 示例2: 使用sync()等待
System.out.println("使用sync()等待...");
try {
future2.sync();
System.out.println("sync() - 操作成功完成");
} catch (InterruptedException e) {
System.out.println("sync() - 被中断");
Thread.currentThread().interrupt();
} catch (Exception e) {
System.out.println("sync() - 操作失败: " + e.getMessage());
}
// 示例3: 使用awaitUninterruptibly()
Future<String> future3 = eventLoop.submit(() -> {
System.out.println("第三个任务开始执行,将耗时1秒");
TimeUnit.SECONDS.sleep(1);
return "第三个任务完成";
});
System.out.println("使用awaitUninterruptibly()等待...");
future3.awaitUninterruptibly();
System.out.println("awaitUninterruptibly() - 操作完成: " +
future3.isSuccess());
} finally {
group.shutdownGracefully();
}
}
}
1.7.3 监听器机制
Netty 的 Future 最强大的特性之一是支持监听器,允许异步处理操作结果而无需阻塞线程:
package cn.tcmeta.future;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import java.util.concurrent.TimeUnit;
/**
* 监听器机制
*/
public class FutureListenerExample {
public static void main(String[] args) throws Exception {
EventLoopGroup group = new NioEventLoopGroup(1);
EventLoop eventLoop = group.next();
try {
// 提交任务并添加监听器
System.out.println("提交任务并添加监听器");
Future<String> future = eventLoop.submit(() -> {
System.out.println("任务执行中...");
TimeUnit.SECONDS.sleep(2);
// 可以模拟成功或失败
// return "任务成功完成";
throw new RuntimeException("任务执行失败");
});
// 添加第一个监听器
future.addListener((GenericFutureListener<? extends Future<? super Object>>) f -> {
System.out.println("\n监听器1: 操作完成");
if (f.isSuccess()) {
System.out.println("监听器1: 操作成功,结果: " + f.getNow());
} else {
System.out.println("监听器1: 操作失败,原因: " +
f.cause().getMessage());
}
});
// 添加第二个监听器
future.addListener(f -> {
System.out.println("\n监听器2: 操作完成");
if (f.isSuccess()) {
System.out.println("监听器2: 执行后续操作...");
} else {
System.out.println("监听器2: 执行错误处理...");
}
});
// 主线程可以继续执行其他操作
System.out.println("\n主线程继续执行其他任务...");
for (int i = 0; i < 5; i++) {
System.out.println("主线程工作中: " + i);
TimeUnit.MILLISECONDS.sleep(500);
}
// 等待所有操作完成
future.awaitUninterruptibly();
System.out.println("\n所有操作处理完毕");
} finally {
group.shutdownGracefully();
}
}
}
提交任务并添加监听器
任务执行中...
主线程继续执行其他任务...
主线程工作中: 0
主线程工作中: 1
主线程工作中: 2
主线程工作中: 3
监听器1: 操作完成
监听器1: 操作失败,原因: 任务执行失败
监听器2: 操作完成
监听器2: 执行错误处理...
主线程工作中: 4
所有操作处理完毕
监听器的执行特性:
- 监听器在对应的 EventLoop 线程中执行
- 多个监听器按添加顺序执行
- 如果操作已完成,添加监听器会立即执行
1.7.4 Future 链式调用(组合异步操作)
package cn.tcmeta.future;
import io.netty.util.concurrent.*;
import java.util.concurrent.TimeUnit;
/**
* 演示 Future 的链式调用
*/
public class FutureChainingExample {
public static void main(String[] args) throws Exception {
EventExecutorGroup group = new DefaultEventExecutorGroup(2);
try {
Future<String> step1 = asyncStep("Step-1", 500, group.next());
Future<String> step2 = step1.addListener((GenericFutureListener<Future<String>>) f -> {
if (f.isSuccess()) {
System.out.println("➡️ Step-1 完成,开始 Step-2");
// Step-2 依赖 Step-1 的结果
asyncStep("Step-2", 300, group.next())
.addListener((GenericFutureListener<Future<String>>) f2 -> {
if (f2.isSuccess()) {
System.out.println("✅ 流程完成: " + f.get() + " -> " + f2.get());
}
});
}
});
step1.await(2, TimeUnit.SECONDS);
} finally {
group.shutdownGracefully();
}
}
private static Future<String> asyncStep(String name, long delay, EventExecutor executor) {
DefaultPromise<String> promise = new DefaultPromise<>(executor);
executor.execute(() -> {
try {
Thread.sleep(delay);
promise.setSuccess(name + "-OK");
} catch (Exception e) {
promise.setFailure(e);
}
});
return promise;
}
}
1.8 底层实现原理剖析
1.8.1 状态机设计
- 一旦状态变更,不可逆
- 保证“承诺”的不可变性
1.8.2 监听器执行模型
- 同步通知:状态变更时立即通知监听器
- EventLoop 线程安全:确保在正确的线程执行回调
- 异常隔离:监听器异常不影响其他监听器
1.8.3 内存可见性保证
- 使用
volatile
关键字确保状态和结果的内存可见性 - 避免 CPU 缓存不一致问题
1.9 最佳实践与常见陷阱
✅ 推荐实践
实践 | 说明 |
---|---|
优先使用 addListener() | 避免阻塞,实现真正的异步 |
避免在 EventLoop 中阻塞 sync() | 防止死锁 |
处理失败情况 | 检查 isSuccess() 和 cause() |
使用 Promise 实现自定义异步逻辑 | 如数据库查询、缓存操作 |
⚠️ 常见错误
// ❌ 错误:在 EventLoop 线程中阻塞
ctx.executor().execute(() -> {
someFuture.sync(); // ❌ 可能导致死锁
});
// ✅ 正确:使用监听器
someFuture.addListener(f -> {
// 处理结果
});
future处理的最佳实践
import io.netty.util.concurrent.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class FutureBestPractices {
// 1. 使用监听器而不是阻塞等待(推荐方式)
public static void processWithListeners(EventExecutor executor) {
Future<Long> future = executor.submit(() -> {
Thread.sleep(1000);
return System.currentTimeMillis();
});
future.addListener(f -> {
if (f.isSuccess()) {
Long result = (Long) f.getNow();
System.out.println("异步结果: " + result);
processResult(result);
} else {
handleFailure(f.cause());
}
});
}
// 2. 必要的同步等待(带超时)
public static Long processWithTimeout(EventExecutor executor) {
Future<Long> future = executor.submit(() -> {
Thread.sleep(2500);
return System.currentTimeMillis();
});
try {
// 总是使用带超时的get方法
return future.get(2, TimeUnit.SECONDS);
} catch (TimeoutException e) {
System.err.println("操作超时,取消任务");
future.cancel(true); // 中断任务执行
return null;
} catch (Exception e) {
System.err.println("操作失败: " + e.getMessage());
return null;
}
}
// 3. 组合多个Future
public static void processMultipleFutures(EventExecutor executor) {
Future<String> future1 = executor.submit(() -> {
Thread.sleep(500);
return "结果1";
});
Future<String> future2 = executor.submit(() -> {
Thread.sleep(800);
return "结果2";
});
// 等待所有Future完成
Future<?> combinedFuture = executor.newPromise().setSuccess(null);
combinedFuture.addListener(f -> {
if (future1.isSuccess() && future2.isSuccess()) {
String result1 = future1.getNow();
String result2 = future2.getNow();
System.out.println("组合结果: " + result1 + ", " + result2);
}
});
}
// 4. 错误处理和重试机制
public static void processWithRetry(EventExecutor executor, int maxRetries) {
AtomicInteger attempt = new AtomicInteger(0);
Future<String> future = executor.submit(() -> {
int currentAttempt = attempt.incrementAndGet();
if (currentAttempt < maxRetries && Math.random() > 0.7) {
throw new RuntimeException("模拟失败,尝试: " + currentAttempt);
}
return "成功结果,尝试: " + currentAttempt;
});
future.addListener(f -> {
if (!f.isSuccess() && attempt.get() < maxRetries) {
System.out.println("尝试失败,准备重试: " + f.cause().getMessage());
// 延迟后重试
executor.schedule(() -> processWithRetry(executor, maxRetries),
1, TimeUnit.SECONDS);
} else if (f.isSuccess()) {
System.out.println("最终成功: " + f.getNow());
} else {
System.err.println("所有重试尝试都失败了");
}
});
}
private static void processResult(Long result) {
System.out.println("处理结果: " + result);
}
private static void handleFailure(Throwable cause) {
System.err.println("处理失败: " + cause.getMessage());
// 记录日志、发送警报等
}
public static void main(String[] args) throws InterruptedException {
EventExecutor executor = new DefaultEventExecutor();
System.out.println("=== 测试监听器模式 ===");
processWithListeners(executor);
System.out.println("=== 测试超时控制 ===");
Long result = processWithTimeout(executor);
System.out.println("超时测试结果: " + result);
System.out.println("=== 测试重试机制 ===");
processWithRetry(executor, 3);
Thread.sleep(5000);
executor.shutdownGracefully();
}
}
1.10 Netty Future 体系的优缺点总结
✅ 优点
优点 | 说明 |
---|---|
真正的异步非阻塞 | 提高性能和吞吐量 |
避免回调地狱 | 通过 Promise 模式链式调用 |
线程安全 | 监听器在正确线程执行 |
资源友好 | 不阻塞线程,支持高并发 |
易于扩展 | 可自定义 Future 实现 |
❌ 缺点
缺点 | 说明 |
---|---|
学习曲线陡峭 | 需理解异步编程模型 |
调试困难 | 堆栈不连续,日志分散 |
错误处理复杂 | 需在每个 Listener 中处理异常 |
过度使用 sync() | 易导致死锁或性能下降 |
1.11 总结:Netty Future 体系的核心价值
维度 | 说明 |
---|---|
核心思想 | 异步操作的结果承诺 + 非阻塞通知 |
关键技术 | 监听器模式、状态机、EventLoop 协同 |
性能优势 | 高并发、低延迟、资源高效 |
设计精髓 | “承诺-完成-通知” 模型 |
适用场景 | 所有异步 I/O 操作、自定义异步任务 |
1.12 一句话总结
💡 一句话总结:
- Netty 的
Future
体系是异步编程的“心脏”- 它通过 监听器模式 和 可写承诺(Promise)
- 将复杂的异步操作转化为清晰、可靠、高效的回调逻辑,是构建高性能网络应用的基石。