1.前言

 第7节讲解JAVA的线程模型中就说到了Future,并解释了为什么可以主线程可以获得线程池任务的执行后结果,变成一种同步状态。秘密就在于Java将所有的runnable和callable任务,统一变成了callable,最终包装成了FutureTask对象,该类实现了Runnable接口和Future接口,所以FutureTask能够被线程执行。最终异步执行过程全部由该类控制逻辑,所以在get的时候锁住了该类,run方法执行的时候释放了锁,这样就满足了能够在异步线程执行完毕获取相关结果的能力。

 本章介绍一下Netty对Future的设计,Netty的声明就是一个异步事件驱动框架,上一节学习了整个线程调度的过程,并在最后给出了前几节的一个综合流程图,虽然图中提到了几种Future,但是没有具体介绍细节,这些将在本节得到解释。

2.相关概念

2.1 Future

 虽然Java中已经定义了Future,但是满足不了Netty的需求,所以Netty新写了一个Future接口,继承了JDK的Future。额外方法定义如下图:

 接口主要追加了两个功能:1.增加了判断任务是否成功失败的方法,以及失败获取异常信息;2.增加了任务完成时触发的监听器

2.2 Promise

 该类继承自Future,自然是增加了额外的功能了:这是一个可写的Future。什么意思呢?通过之前的知识,我们知道Future都是由异步线程控制的,主线程是无法控制线程执行的。Promise的作用就是主线程能够控制一下执行的任务。

  setSuccess():标记任务成功,并触发所有listener。如果任务早就成功或失败,则抛出异常

  trySuccess():同上,但是失败只是返回false,而不是抛出异常

 这里就解释这两个方法,其他方法是覆盖了父接口的方法,确定返回的具体类型而已。根据方法我们也能大体明白可写的含义了。

3 主要Future详解

3.1 DefaultChannelPromise

 该类是在注册channel时创建的,SingleThreadEventLoop的register方法。和Java的FutureTask不同,FutureTask是作为一个任务交给线程池,在内部控制任务执行。DefaultChannelPromise则是持有了Channel和EventExecutor二者,在外边处理逻辑。其上层有2个抽象父类:

  1.AbstractFuture:

    该类就实现了get方法,原理是调用了await()方法,await之后唤醒肯定就是任务结束了,判断有无异常,最终返回结果还是抛出异常。

  2.DefaultPromise:

    该类提供了一个Promise应该具备的基本实现。对任务标记结果,触发listener等。其主要有个result,对结果进行CAS操作来判断任务是否完成。

    setSuccess过程如下:1.设置成功的结果;2.触发所有的listener。设置结果主要是CAS更新result字段,然后判断是否有get请求等待任务执行完,直接notifyAll即可。触发listener的过程在于先判断当前线程是否是事件线程中,触发方法必须由EventLoop线程执行,然后就是遍历触发listener的operationComplete方法。

    await过程如下:1.判断是否执行完,执行完直接返回;2.判断线程是否中断,中断抛出异常;3.检查死锁,即wait操作不能在EventLoop的线程中执行;4.如果没执行完,等待者计数,然后wait。

 DefaultChannelPromise相对于DefaultPromise而言只是增加了一个channel字段,其它的方法都是调用父类方法。接下来我们看看register过程是怎么使用这个Promise的吧。

    public final void register(EventLoop eventLoop, final ChannelPromise promise) {
if (eventLoop == null) {
throw new NullPointerException("eventLoop");
}
if (isRegistered()) {
promise.setFailure(new IllegalStateException("registered to an event loop already"));
return;
}
if (!isCompatible(eventLoop)) {
promise.setFailure(
new IllegalStateException("incompatible event loop type: " + eventLoop.getClass().getName()));
return;
} AbstractChannel.this.eventLoop = eventLoop; if (eventLoop.inEventLoop()) {
register0(promise);
} else {
try {
eventLoop.execute(new Runnable() {
@Override
public void run() {
register0(promise);
}
});
} catch (Throwable t) {
logger.warn(
"Force-closing a channel whose registration task was not accepted by an event loop: {}",
AbstractChannel.this, t);
closeForcibly();
closeFuture.setClosed();
safeSetFailure(promise, t);
}
}
}

 可以看到在注册过程中实际上就是使用setXXX方法来处理相关逻辑的,这个和Java的FutureTask采取了不同的方式。

3.2 SucceededFuture

 上面讲了一个Promise控制主线程和线程池的同步状态,那个是依靠promise才有的setXXX接口来触发的。那么Future是怎么控制的呢?答案是Future不需要控制,返回Future的时候就已经有结果了,并且返回一定是一个同步过程。

 以SucceededFuture为例。Bootstrap中的doResolveAndConnect0方法有段:final Future<SocketAddress> resolveFuture = resolver.resolve(remoteAddress);其解析成功就会返回带有结果的SucceededFuture。看这个类的sync方法也和Promise的不一样,Promise是await,Future是直接返回。这个可以说明Future和Promise的区别:Future用于同步任务,Promise用于异步任务。不知道Netty为什么会设计成这样,让人会有些疑惑。但是记住这点,再加上Promise的set方法达成的效果,就可以理解Netty的Future了。

4.总结

 Netty的Future设计采取了和Java的FutureTask不同的设计思路。Java的思路是将Futuren包装成一个任务,这样异步线程执行这个FutureTask的时候,其就可以知道任务的执行状态。Netty将Future扩展成了Promise。Future作为同步方法直接返回的结果类,使用较少。Promise提供了setXXX方法,给异步线程调用该方法告知执行状态。相同的地方在于Promise也必须被异步线程持有,才能使用set方法。

Netty核心概念(9)之Future的更多相关文章

  1. Netty In Action中文版 - 第三章:Netty核心概念

            在这一章我们将讨论Netty的10个核心类.清楚了解他们的结构对使用Netty非常实用.可能有一些不会再工作中用到.可是也有一些非经常常使用也非常核心,你会遇到. Bootstrap ...

  2. Netty核心概念(8)之Netty线程模型

    1.前言 第7节初步学习了一下Java原本的线程池是如何工作的,以及Future的为什么能够达到其效果,这些知识对于理解本章有很大的帮助,不了解的可以先看上一节. Netty为什么会高效?回答就是良好 ...

  3. Netty核心概念(7)之Java线程池

    1.前言 本章本来要讲解Netty的线程模型的,但是由于其是基于Java线程池设计而封装的,所以我们先详细学习一下Java中的线程池的设计.之前也说过Netty5被放弃的原因之一就是forkjoin结 ...

  4. Netty核心概念(10)之内存管理

    1.前言 之前的章节已经将启动demo中能看见的内容都分析完了,Netty的一个整体样貌都在第8节线程模型最后给的图画出来了.这些内容解释了Netty为什么是一个异步事件驱动的程序,也解释了Netty ...

  5. Netty核心概念(6)之Handler

    1.前言 本节介绍Netty中第三个重要的概念——Handler,这个在前两节都提到了,尤其是Channel和Handler联系紧密.handler本身的设计非常简单,但是所起到的作用却很大,Nett ...

  6. Netty核心概念(5)之Channel

    1.前言 上一节讲了Netty的第一个关键启动类,启动类所做的一些操作,和服务端的channel固定的handler执行过程,谈到了不管是connect还是bind方法最终都是调用了channel的相 ...

  7. Netty核心概念(4)之Bootstrap

    1.前言 第三节介绍了Netty的一些基本概念,此节介绍Netty的第一个概念Bootstrap——启动类.Netty中服务端和客户端的启动类是不一样的,这个不要搞错了,类都在bootstrap包下. ...

  8. Netty核心概念

    一个Netty程序始于Bootstrap类,Bootstrap类是Netty提供的一个可以通过简单配置来设置或“引导”程序的一个重要的类.Netty中设计了Handlers来处理特定的"ev ...

  9. 消息中间件——RabbitMQ(三)理解RabbitMQ核心概念和AMQP协议!

    前言 本章学习,我们可以了解到以下知识点: 互联网大厂为什么选择RabbitMQ? RabbiMQ的高性能之道是如何做到的? 什么是AMQP高级协议? AMQP核心概念是什么? RabbitMQ整体架 ...

随机推荐

  1. Excel获得焦点变色

    1.  点击 Sheet 2. 右键菜单  查看代码 3. 复制如下代码 Private Sub Worksheet_SelectionChange(ByVal Target As Excel.Ran ...

  2. com.liuyang.exception.DaoException: java.sql.SQLException: Incorrect string

    错误是在JUnit测试的时候产生的,但是实际加入数据也会产生这样的情况,主要是数据库内部的编码方式不支持当前的编码方式导致的冲突,解决方法就是在建立数据库之前,要查看当前的数据库的编码方式,方法和更改 ...

  3. centos6 mysql 安装与配置

    MySQL简介: 由于其体积小.速度快.总体拥有成本低,尤其是开放源码这一特点,许多中小型网站为了降低网站总体拥有成本而选择了MySQL作为网站数据库.MySQL是一个多用户.多线程的关系型数据库管理 ...

  4. 12) maven-compiler-plugin

    The Compiler Plugin is used to compile the sources of your project. At present the default source se ...

  5. 第二届普适计算和信号处理及应用国际会议论文2016年 The 2nd Conference on Pervasive Computing, Signal Processing and Applications(PCSPA, 2016)

    A New Method for Mutual Coupling Correction of Array Output Signal 一种阵列输出信号互耦校正的新方法 Research of Robu ...

  6. noip第8课作业

    1.     计算书费 [问题描述]下面是一个图书的单价表: 计算概论 28.9 元/本 数据结构与算法 32.7 元/本 数字逻辑 45.6元/本 C++程序设计教程 78 元/本 人工智能 35  ...

  7. hdu 4982 贪心构造序列

    http://acm.hdu.edu.cn/showproblem.php?pid=4982 给定n和k,求一个包含k个不相同正整数的集合,要求元素之和为n,并且其中k-1的元素的和为完全平方数 枚举 ...

  8. SpringMVC 示例实战教程

    一.SpringMVC基础入门,创建一个HelloWorld程序 1.首先,导入SpringMVC需要的jar包. 2.添加Web.xml配置文件中关于SpringMVC的配置 1 2 3 4 5 6 ...

  9. TFS 2015 生成不输出任何结果

    这是一台用于测试的TFS 2015服务器,其中的数据是通过备份和还原,在使用应用层专用的方式配置出来的. 在配置完成代理服务器以后,运行生成,发现在获取代码之前就停止失败了,并且在生成过程中没有任何结 ...

  10. centos:开启和关闭selinux

    5.4. Enabling and Disabling SELinux Use the /usr/sbin/getenforce or /usr/sbin/sestatus commands to c ...