Netty中trySuccess和setSuccess的区别
io.netty.util.concurrent.DefaultPromise#trySuccess
和 io.netty.util.concurrent.DefaultPromise#setSuccess
是 Netty 中 DefaultPromise
类的两个方法,用于设置异步操作(Promise
)的成功结果。两者都属于 Promise
接口的实现,用于通知异步操作完成并设置结果,但它们在行为、语义和使用场景上有关键区别。
1. 方法定义
1.1 trySuccess
- 包:
io.netty.util.concurrent
- 类:
io.netty.util.concurrent.DefaultPromise
- 方法签名:
boolean trySuccess(V result);
- 返回值:
boolean
(true
表示成功设置结果,false
表示设置失败) - 描述:尝试将
Promise
设置为成功状态并存储结果。如果Promise
尚未完成(即result
字段为null
),则设置成功并返回true
;如果已完成(成功或失败),则返回false
,不修改状态。
1.2 setSuccess
- 包:
io.netty.util.concurrent
- 类:
io.netty.util.concurrent.DefaultPromise
- 方法签名:
Promise<V> setSuccess(V result);
- 返回值:
Promise<V>
(返回this
,支持链式调用) - 描述:将
Promise
设置为成功状态并存储结果。如果Promise
尚未完成,设置成功并返回this
;如果已完成,抛出IllegalStateException
。
2. 源码分析与注释
2.1 trySuccess
源码
以下是 DefaultPromise#trySuccess
的源码
源码注释:
/*** 尝试将 Promise 设置为成功状态并存储结果。* 如果 Promise 尚未完成(result == null),设置成功并返回 true。* 如果 Promise 已完成(成功、失败或取消),返回 false,不修改状态。* @param result 成功的结果* @return true 表示设置成功,false 表示设置失败*/
@Override
public boolean trySuccess(V result) {if (trySuccessInternal(result)) { // 尝试设置结果notifyListeners(); // 通知监听器return true;}return false;
}/*** 内部方法,执行设置成功结果的逻辑。* @param result 要设置的结果* @return true 表示设置成功,false 表示设置失败*/
private boolean trySuccessInternal(Object result) {return trySetResult(result, false); // 调用 trySetResult
}/*** 尝试设置 Promise 的结果。* @param result 要设置的结果* @param wasCancelled 是否为取消操作* @return true 表示设置成功,false 表示设置失败*/
private boolean trySetResult(Object result, boolean wasCancelled) {synchronized (this) { // 确保线程安全// 检查 Promise 是否已完成(result != null)// 如果 wasCancelled 为 true,仅允许在 result == CANCELLED 时覆盖if (this.result != null && (!wasCancelled || this.result != CANCELLED)) {return false; // 已完成,返回 false}this.result = result; // 设置结果checkNotifyWaiters(); // 检查并唤醒等待线程return true;}
}
2.2 setSuccess
源码
以下是 DefaultPromise#setSuccess
的源码:
源码注释:
/*** 将 Promise 设置为成功状态并存储结果。* 如果 Promise 尚未完成,设置成功并返回 this。* 如果 Promise 已完成,抛出 IllegalStateException。* @param result 成功的结果* @return 当前 Promise 实例* @throws IllegalStateException 如果 Promise 已完成*/
@Override
public Promise<V> setSuccess(V result) {if (setSuccess0(result)) { // 尝试设置结果notifyListeners(); // 通知监听器return this; // 返回 Promise 实例}throw new IllegalStateException("complete already: " + this); // 已完成,抛出异常
}/*** 内部方法,执行设置成功结果的逻辑。* @param result 要设置的结果* @return true 表示设置成功,false 表示设置失败*/
private boolean setSuccess0(Object result) {return setResult0(result, false); // 调用 setResult0
}/*** 设置 Promise 的结果。* @param result 要设置的结果* @param wasCancelled 是否为取消操作* @return true 表示设置成功,false 表示设置失败*/
private boolean setResult0(Object result, boolean wasCancelled) {synchronized (this) { // 确保线程安全// 检查 Promise 是否已完成if (this.result != null && (!wasCancelled || this.result != CANCELLED)) {return false; // 已完成,返回 false}this.result = result; // 设置结果checkNotifyWaiters(); // 检查并唤醒等待线程return true;}
}
3. 关键区别
trySuccess
和 setSuccess
的核心区别在于对已完成状态的处理方式和返回值语义。以下是详细对比:
特性 | trySuccess | setSuccess |
---|---|---|
返回值 | boolean (true 表示成功,false 表示失败) | Promise<V> (返回 this ,支持链式调用) |
已完成时的行为 | 返回 false ,不抛出异常 | 抛出 IllegalStateException |
线程安全 | 使用 synchronized 确保线程安全 | 使用 synchronized 确保线程安全 |
通知监听器 | 成功设置时调用 notifyListeners() | 成功设置时调用 notifyListeners() |
唤醒等待线程 | 成功设置时调用 checkNotifyWaiters() | 成功设置时调用 checkNotifyWaiters() |
使用场景 | 允许多次尝试设置结果,适合竞争性场景 | 确保结果只设置一次,适合确定性场景 |
异常处理 | 无异常,失败时静默返回 false | 失败时抛出 IllegalStateException |
3.1 行为差异
-
trySuccess
:- 非强制性:尝试设置结果,如果
Promise
已完成(result != null
),返回false
,不会抛出异常。 - 适合在多个线程可能竞争设置结果的场景,例如多个线程尝试完成同一个
Promise
。 - 示例:多个异步任务可能同时尝试设置结果,只有一个会成功。
- 非强制性:尝试设置结果,如果
-
setSuccess
:- 强制性:要求设置结果必须成功,如果
Promise
已完成,抛出IllegalStateException
。 - 适合在明确知道
Promise
未完成且只应由一个线程设置结果的场景。 - 示例:
AbstractUnsafe#register
中使用setSuccess
确保注册操作只完成一次。
- 强制性:要求设置结果必须成功,如果
3.2 性能差异
- 开销:两者性能差异微小,都使用
synchronized
确保线程安全。 trySuccess
更灵活,适合需要检查状态的场景。setSuccess
更严格,适合需要确保单一设置的场景,但抛出异常可能增加调用方的错误处理成本。
4. 使用场景
4.1 trySuccess
- 竞争性场景:
- 多个线程可能同时尝试设置
Promise
的结果,只有第一个成功的线程生效。 - 示例:多个异步任务处理同一个
Promise
,如并发连接尝试。
- 多个线程可能同时尝试设置
- 容错性要求:
- 允许调用方处理设置失败的情况(通过检查
false
返回值)。 - 示例:在分布式系统中,多个节点尝试完成同一个异步操作。
- 允许调用方处理设置失败的情况(通过检查
- 代码示例:
DefaultPromise<String> promise = new DefaultPromise<>(eventLoop); // 线程 1 boolean success = promise.trySuccess("Result from thread 1"); System.out.println("Thread 1 success: " + success); // true // 线程 2 success = promise.trySuccess("Result from thread 2"); System.out.println("Thread 2 success: " + success); // false
4.2 setSuccess
- 单一设置场景:
- 确保
Promise
只由一个线程设置结果,通常在明确控制流的场景。 - 示例:在
AbstractUnsafe#register
中,注册完成后由EventLoop
线程设置ChannelPromise
成功。
- 确保
- 严格控制:
- 要求
Promise
未完成,抛出异常以强制调用方检查状态。 - 示例:Netty 内部操作(如
Channel
初始化)确保单一完成。
- 要求
- 代码示例:
DefaultPromise<String> promise = new DefaultPromise<>(eventLoop); promise.setSuccess("Result"); // 成功设置 try {promise.setSuccess("Another result"); // 抛出 IllegalStateException } catch (IllegalStateException e) {System.err.println("Promise already completed: " + e.getMessage()); }