异步获取线程执行结果,JDK中的Future、Netty中的Future和Promise对比

JDK中的Future和Netty中的Future、Promise的关系

三者源头追溯

        Netty中的Future与JDK中的Future同名,但是是两个不同的接口。Netty中的Future继承自JDK的Future,而Promise又对Netty中的Future进行了扩展。

  • JDK中的Future源自JUC并发包:

  • Netty中的Future源自Netty中的并发包:import io.netty.util.concurrent.Future; 并继承JUC中的Future。

  • Netty中的Promise继承自Netty中的Future,并且是一个接口,下面有一个实现类DefaultPromise<V>:

三者之间的区别和联系

  • jdk Future 只能同步等待任务结束(或成功、或失败)才能得到结果

  • netty Future 可以同步等待任务结束得到结果,也可以异步方式得到结果,但都是要等任务结束

  • netty Promise 不仅有 netty Future 的功能,而且脱离了任务独立存在,只作为两个线程间传递结果的容器

  • JDK和Netty中的Future并不是自己创建的,而是执行任务的线程执行结束后自己创建并且返回的。对于Future的创建权以及结果的设置均不是自己控制的,而是执行任务的线程控制的。Netty中的Promise可以提交者自己创建随后作为一个容器,供其他线程使用。

 代码演示

JDK中的Future

        代码编写:

        JDK中Future的获取依赖于线程池,首先创建线程池。

package com.example.code.netty.c4;

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

@Slf4j
public class TestJDKFuture {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService service = Executors.newFixedThreadPool(2);
        // future的理解,就是线程之间通信的工具,一个线程中获取另一个线程的结果,需要另一个线程主动填充
        log.info("task begin ...");
        Future<Integer> future = service.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                log.info("task is running...");
                Thread.sleep(1000);
                // future是被动获取结果的,需要执行任务的线程向future中填充返回结果
                log.info("task is end ...");
                return 20;
            }
        });
        log.info("等待结果...");
        log.info("获取任务执行结果:{}", future.get());
    }
}

        结果展示:

        通过lombok中的@Slf4j注解,打印执行过程相关信息:主要关注①执行线程名称,②任务执行是都异步,获取结果是否是阻塞、同步。执行顺序如下所示:

         上述图片中的②和③执行顺序不能倒置,②属于主线程顺序执行,然而③属于新创建的线程中执行,线程的创建以及启动本身需要耗费一定的时间。

Netty中的Future

        Netty中的Future的获取依赖于EventLoop,需要首先创建EventLoop,等价于JDK中的Future的获取的线程池的创建。

        Netty中的Future对于结果的获取可以采用同步,也可也采用异步的方式。并且在异步获取结果时可以使用get()、getNow()两种方式获取。

  • get():获取任务结果,阻塞等待。
  • getNow():获取任务结果,非阻塞,还未产生结果时返回null。
package com.example.code.netty.c4;

import io.netty.channel.EventLoop;
import io.netty.channel.EventLoopGroup;
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 TestNettyFuture {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
        EventLoop eventLoop = eventLoopGroup.next();
        Future<Integer> future = eventLoop.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                log.info("task is running...");
                Thread.sleep(1000);
                // future是被动获取结果的,需要执行任务的线程向future中填充返回结果
                log.info("task is end ...");
                return 70;
            }
        });

        log.info("等待结果...");
        // 同步方式获取任务执行结果
//        log.info("获取任务执行结果:{}", future.get());
        // 异步方式获取执行结果
        future.addListener(new GenericFutureListener<Future<? super Integer>>() {
            @Override
            public void operationComplete(Future<? super Integer> future) throws Exception {
                // 异步获取执行结果既可以用future.get()阻塞方法,也可以用future.getNow()非阻塞方法。
                // 异步既然执行到了回调函数这一步,肯定已经能够获取到执行结果。
                log.info("获取任务执行结果:{}", future.getNow());
            }
        });
    }
}

        代码执行结果:【同步】

        代码执行结果:【异步】 

        同步方式下最终任务执行结果70的获取线程是当前main线程,而异步方式下最终执行结果70的获取是在nioEventLoopGroup中的某个线程也即任务线程本身中获取。 

Netty中的Promise

        Netty中的Promise继承自Netty中的Future,在继承Future相关功能的基础上,又实现了功能的增强。不仅可以在任务正确执行后设置执行结果,也可以在任务执行失败后设置执行结果。

  • setSuccess():设置成功结果。
  • setFailure():设置失败结果。

        代码编写:

package com.example.code.netty.c4;

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 TestNettyPromise {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        EventLoop eventLoop = new NioEventLoopGroup().next();
        // 主动创建promise,结果容器
        DefaultPromise<Integer> promise = new DefaultPromise<>(eventLoop);
        log.info("task begin ...");
        new Thread(()->{
            log.info("task is running...");
            // 任意一个线程执行计算,计算完毕后向promise中填充结果。
            try {
//                int i = 1 / 0;
                Thread.sleep(1000);
                promise.setSuccess(10);
            } catch (Exception e) {
//                e.printStackTrace();
                promise.setFailure(e);
            }
            log.info("task end ...");
        }).start();
        log.info("等待结果...");
        log.info("获取任务执行结果:{}", promise.get());
    }
}

        代码执行结果:【同步】,异步执行结果不再演示,同Netty中的Future效果所示。

  • 22
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,让我来为您解答这个问题。 首先,需要明确的是,JDK17和NettyJava开发非常常用的工具和框架,而Spring Boot是一个基于Spring框架的快速开发工具,可以帮助我们快速搭建Java Web应用程序。 接下来,我将为您提供一个使用JDK17、Netty和Spring Boot搭建IoT项目的简单实例: 1. 确保您已经安装好了JDK17,并且已经配置好了环境变量。 2. 创建一个Spring Boot项目,可以使用工具如IntelliJ IDEA或Eclipse。在创建项目时,选择Maven或Gradle构建工具。 3. 在项目添加Netty依赖,可以在pom.xml或build.gradle文件添加以下依赖: ``` <!-- Maven --> <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.43.Final</version> </dependency> // Gradle compile group: 'io.netty', name: 'netty-all', version: '4.1.43.Final' ``` 4. 创建IoT服务类,例如MyIoTServer: ``` @Component public class MyIoTServer { @Value("${netty.port}") private int port; public void start() throws InterruptedException { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new MyIoTServerHandler()); } }); ChannelFuture channelFuture = serverBootstrap.bind(port).sync(); channelFuture.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } } } ``` 5. 创建IoT服务处理器类,例如MyIoTServerHandler: ``` @Component public class MyIoTServerHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { // 处理接收到的消息 } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { // 处理异常 } } ``` 6. 在application.properties或application.yml文件配置Netty端口号: ``` # application.properties netty.port=8080 # application.yml netty: port: 8080 ``` 7. 在启动类启动IoT服务: ``` @SpringBootApplication public class MyApplication { public static void main(String[] args) throws InterruptedException { ApplicationContext context = SpringApplication.run(MyApplication.class, args); MyIoTServer myIoTServer = context.getBean(MyIoTServer.class); myIoTServer.start(); } } ``` 以上就是一个使用JDK17、Netty和Spring Boot搭建IoT项目的简单实例。当然,这只是一个初步的示例,实际开发还需要根据具体需求进行相关的配置和开发。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值