Netty笔记04-组件Future & Promise


前言

在 Netty 中,Future 和 Promise 是用于处理异步操作结果的重要组件。
首先要说明 netty 中的 Future 与 jdk 中的 Future 同名,但是是两个接口,netty 的 Future 继承自 jdk 的 Future,而 Promise 又对 netty Future 进行了扩展

  • jdk Future 只能同步等待任务结束(或成功、或失败)才能得到结果
  • netty Future 可以同步等待任务结束得到结果,也可以异步方式得到结果,但都是要等任务结束
  • netty Promise 不仅有 netty Future 的功能,而且脱离了任务独立存在,只作为两个线程间传递结果的容器

Future

Future 是一个表示异步操作结果的对象。它提供了一种机制来查询异步操作是否已经完成,并且可以获取操作的结果或者抛出的异常。Future 接口在 Java 标准库中也有实现(java.util.concurrent.Future),但 Netty 提供了自己的 Future 实现,更加符合其异步事件驱动的设计理念。

主要方法

boolean isDone():判断异步操作是否已经完成。
boolean isSuccess():判断异步操作是否成功完成。
boolean isCancelled():判断异步操作是否已被取消。
V get():阻塞等待异步操作完成,并返回结果或抛出异常。
V get(long timeout, TimeUnit unit):在指定时间内阻塞等待异步操作完成,并返回结果或抛出异常。

ChannelFuture future = channel.writeAndFlush(msg);
future.addListener((ChannelFutureListener) future1 -> {
    if (future1.isSuccess()) {
        System.out.println("Write and flush completed successfully.");
    } else {
        System.out.println("Write and flush failed.");
        future1.cause().printStackTrace();
    }
});

Promise

Promise 是 Netty 特有的一个接口,它扩展了 Future 接口,并提供了额外的方法来控制异步操作的状态。Promise 通常由 EventLoop 使用来完成异步操作,并通知 Future 的监听者。

主要方法

Promise< V >:这是一个泛型接口,表示异步操作的结果类型。
void setSuccess(V result):设置异步操作成功完成,并传入结果。
void setFailure(Throwable cause):设置异步操作失败,并传入异常。
void setUncancellable():设置异步操作不可取消。
void cancel(boolean mayInterruptIfRunning):取消异步操作。
ChannelFuture addListener(GenericFutureListener<? extends Future<? super V>> listener):添加一个监听器,当异步操作完成时调用。

ChannelPromise promise = channel.newPromise();
channel.writeAndFlush(msg, promise).addListener((ChannelFutureListener) future -> {
    if (future.isSuccess()) {
        System.out.println("Write and flush completed successfully.");
    } else {
        System.out.println("Write and flush failed.");
        future.cause().printStackTrace();
    }
});

Future 和 Promise 的区别

  • Future 是一个只读的接口,它只能用来查询异步操作的状态和结果。
  • Promise 是一个可写的接口,除了可以查询状态和结果外,还可以设置操作的结果或异常。

使用场景

  • Future 通常用于消费异步操作的结果,例如在完成某个异步操作后执行某些逻辑。
  • Promise 通常用于生产异步操作的结果,例如在某个异步操作完成后,通过 Promise 设置结果或异常。

代码示例

Jdk中的Future

import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.*;

@Slf4j
public class Test02JdkFuture {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 1. 创建线程池
        ExecutorService service = Executors.newFixedThreadPool(2);
        // 2. 提交任务
        Future<Integer> future = service.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                log.debug("执行计算");//[DEBUG] [pool-1-thread-1] c.i.n.c.Test02JdkFuture - 执行计算
                Thread.sleep(1000);
                return 50;
            }
        });
        // 3. 主线程通过 future 来获取结果
        log.debug("等待结果");//[DEBUG] [main] c.i.n.c.Test02JdkFuture - 等待结果
        log.debug("结果是 {}", future.get());//[DEBUG] [main] c.i.n.c.Test02JdkFuture - 结果是 50
    }
}

Netty中的Future

import io.netty.channel.EventLoop;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;

@Slf4j
public class Test03NettyFuture {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        NioEventLoopGroup group = new NioEventLoopGroup();
        EventLoop eventLoop = group.next();
        Future<Integer> future = eventLoop.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                log.debug("执行计算");//[DEBUG] [nioEventLoopGroup-2-1] c.i.n.c.Test03NettyFuture - 执行计算
                Thread.sleep(1000);
                return 70;
            }
        });
        //使用同步的方式(主线程中拿结果)
//        log.debug("等待结果");//[DEBUG] [main] c.i.n.c.Test03NettyFuture - 等待结果
//        log.debug("结果是 {}", future.get());//[DEBUG] [main] c.i.n.c.Test03NettyFuture - 结果是 70

        //使用异步的方式(执行线程中拿结果)
        future.addListener(new GenericFutureListener<Future<? super Integer>>(){
            @Override
            public void operationComplete(Future<? super Integer> future) throws Exception {
                log.debug("接收结果:{}", future.getNow());//[DEBUG] [nioEventLoopGroup-2-1] c.i.n.c.Test03NettyFuture - 接收结果:70
            }
        });
    }
}

Netty中的Promise

import io.netty.channel.EventLoop;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.util.concurrent.DefaultPromise;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.ExecutionException;

@Slf4j
public class Test04NettyPromise {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 1. 准备 EventLoop 对象
        EventLoop eventLoop = new NioEventLoopGroup().next();
        // 2. 可以主动创建 promise, promise是一个结果容器
        DefaultPromise<Integer> promise = new DefaultPromise<>(eventLoop);
        new Thread(() -> {
            // 3. 任意一个线程执行计算,计算完毕后向 promise 填充结果
            log.debug("开始计算...");//[DEBUG] [Thread-0] c.i.n.c.Test04NettyPromise - 开始计算...
            try {
                int i = 1 / 0;
                Thread.sleep(1000);
                promise.setSuccess(80);
            } catch (Exception e) {
                e.printStackTrace();
                promise.setFailure(e);//传递异常
            }
        }).start();
        // 4. 接收结果的线程
        log.debug("等待结果...");//[DEBUG] [main] c.i.n.c.Test04NettyPromise - 等待结果...
        //有异常则直接发出异常
        log.debug("结果是: {}", promise.get());//[DEBUG] [main] c.i.n.c.Test04NettyPromise - 结果是: 80
    }
}

同步处理任务失败 - await

DefaultEventLoop eventExecutors = new DefaultEventLoop();
DefaultPromise<Integer> promise = new DefaultPromise<>(eventExecutors);

eventExecutors.execute(() -> {
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    RuntimeException e = new RuntimeException("error...");
    log.debug("set failure, {}", e.toString());
    promise.setFailure(e);
});

log.debug("start...");
log.debug("{}", promise.getNow());
promise.await(); // 与 sync 和 get 区别在于,不会抛异常
log.debug("result {}", (promise.isSuccess() ? promise.getNow() : promise.cause()).toString());

输出

12:18:53 [DEBUG] [main] c.i.o.DefaultPromiseTest2 - start...
12:18:53 [DEBUG] [main] c.i.o.DefaultPromiseTest2 - null
12:18:54 [DEBUG] [defaultEventLoop-1-1] c.i.o.DefaultPromiseTest2 - set failure, java.lang.RuntimeException: error...
12:18:54 [DEBUG] [main] c.i.o.DefaultPromiseTest2 - result java.lang.RuntimeException: error...

异步处理任务失败

DefaultEventLoop eventExecutors = new DefaultEventLoop();
DefaultPromise<Integer> promise = new DefaultPromise<>(eventExecutors);

promise.addListener(future -> {
    log.debug("result {}", (promise.isSuccess() ? promise.getNow() : promise.cause()).toString());
});

eventExecutors.execute(() -> {
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    RuntimeException e = new RuntimeException("error...");
    log.debug("set failure, {}", e.toString());
    promise.setFailure(e);
});

log.debug("start...");

输出

12:04:57 [DEBUG] [main] c.i.o.DefaultPromiseTest2 - start...
12:04:58 [DEBUG] [defaultEventLoop-1-1] c.i.o.DefaultPromiseTest2 - set failure, java.lang.RuntimeException: error...
12:04:58 [DEBUG] [defaultEventLoop-1-1] c.i.o.DefaultPromiseTest2 - result java.lang.RuntimeException: error...

  • 13
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Netty-WebSocket-Spring-Boot-Starter是一个用于将Websocket集成到Spring Boot应用程序中的库。它使用Netty作为底层框架,提供了一种快速和可靠的方式来处理异步通信。 这个库提供了一种简单的方法来创建Websocket端点,只需要使用注释和POJO类即可。在这些端点上可以添加动态的事件处理程序,以处理连接、断开连接和消息事件等。 此外,Netty-WebSocket-Spring-Boot-Starter还包括了一些安全性的特性,如基于令牌的授权和XSS保护,可以帮助您保持您的Websocket应用程序安全。 总的来说,Netty-WebSocket-Spring-Boot-Starter提供了一种快速和易于使用的方式来构建Websocket应用程序,使得它成为应用程序开发人员的有用工具。 ### 回答2: netty-websocket-spring-boot-starter 是一个开源的 Java Web 开发工具包,主要基于 Netty 框架实现了 WebSocket 协议的支持,同时集成了 Spring Boot 框架,使得开发者可以更加方便地搭建 WebSocket 服务器。 该工具包提供了 WebSocketServer 配置类,通过在 Spring Boot 的启动配置类中调用 WebSocketServer 配置类,即可启动 WebSocket 服务器。同时,该工具包还提供了多种配置参数,如端口号、URI 路径、SSL 配置、认证配置等等,可以根据业务需求进行自定义配置。 此外,该工具包还提供了一些可扩展的接口和抽象类,如 WebSocketHandler、ChannelHandlerAdapter 等,可以通过继承和实现这些接口和抽象类来实现业务逻辑的处理和拓展。 总的来说,netty-websocket-spring-boot-starter 提供了一个高效、简单、易用的 WebSocket 服务器开发框架,可以减少开发者的开发成本和工作量。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值