参考文献:极客时间傅健老师的《Netty源码剖析与实战》Talk is cheap.show me the code!

三种I/O模式

  BIO:Block I/O,即同步并阻塞的IO;BIO就是传统的java.io包下的代码实现

  NIO:New IO(non-blocking IO):同步非阻塞的IO,jdk1.4及以上版本提供

  AIO:Async IO: 异步非阻塞IO,jdk1.7

阻塞和非阻塞

   阻塞:没有数据传输过来时,读会阻塞直到有数据;缓冲区满时,写操作也会阻塞。

  非阻塞: 非阻塞遇到这些情况都是直接返回。

同步和异步

  同步:数据就绪后需要自己去读是同步。

  异步:数据就绪后直接读好再回调给程序是异步。

Netty对三种IO的支持

  

首先Netty是都支持三种IO模式的,准确的来说是曾经都支持过,因为BIO的被Netty给过期了,AIO被Netty给删除了,具体原因这就不多赘述;知道BIO在Netty被称为OIO,NIO在多平台下都有对应的支持,有人会问为啥有common的支持了还有Linux等其他的意义吗,这好比全栈和后端前端之分一样,一个通用一个专用的区别。

Netty切换IO模式

  如上图所示,对应的实现类都差不多,甚至可以看出都是头不一样,如果NIO的通用是NioEventLoopGroup,而OIO的实现则是OioEventLoopGroup,先看之前的一个demo

public class MyServer {
public static void main(String[] args) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap sb = new ServerBootstrap();
sb.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO)).childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(new LoggingHandler(LogLevel.INFO));
p.addLast(new MyServerHandler());
}
});
ChannelFuture f = sb.bind(8090).sync();
f.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}

  图上标粗的就是切换的模式的关键点。现在看看切换成OIO的代码

public class MyServer {
public static void main(String[] args) throws Exception {
EventLoopGroup bossGroup = new OioEventLoopGroup();
EventLoopGroup workerGroup = new OioEventLoopGroup();
try {
ServerBootstrap sb = new ServerBootstrap();
sb.group(bossGroup, workerGroup).channel(OioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO)).childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(new LoggingHandler(LogLevel.INFO));
p.addLast(new MyServerHandler());
}
});
ChannelFuture f = sb.bind(8090).sync();
f.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}

  上面代码改动也就是标粗的那些。运行起来是完全没问题的。

  那么具体是怎么做的呢,我们看看源码就知道了;

  点进channel()方法里,核心步骤在此:

  不难发现传入的是OioServerSocketChannel.class,由channelFactory工厂创建返回,进入ReflectiveChannelFactory();

上图的代码中有“this.constructor = clazz.getConstructor();”获取无参构造;

可以看出“return constructor.newInstance();”返回泛型“T” 就是要使用的IO模式。

总结来说:Netty实现IO模式的切换就是泛型+反射+工厂实现的。

除此之外,还有一点,"EventLoopGroup bossGroup = new NioEventLoopGroup();";实际上,它就相当于一个死循环,在“NioEventLoop.java”中,有个run(),如下图源码,可以看出它是个死循环(for (;;) {}),现在可以简单的理解它就是循环监听、处理事件的。

@Override
protected void run() {
for (;;) {
try {
try {
switch (selectStrategy.calculateStrategy(selectNowSupplier, hasTasks())) {
case SelectStrategy.CONTINUE:
continue; case SelectStrategy.BUSY_WAIT:
// fall-through to SELECT since the busy-wait is not supported with NIO case SelectStrategy.SELECT:
select(wakenUp.getAndSet(false)); // 'wakenUp.compareAndSet(false, true)' is always evaluated
// before calling 'selector.wakeup()' to reduce the wake-up
// overhead. (Selector.wakeup() is an expensive operation.)
//
// However, there is a race condition in this approach.
// The race condition is triggered when 'wakenUp' is set to
// true too early.
//
// 'wakenUp' is set to true too early if:
// 1) Selector is waken up between 'wakenUp.set(false)' and
// 'selector.select(...)'. (BAD)
// 2) Selector is waken up between 'selector.select(...)' and
// 'if (wakenUp.get()) { ... }'. (OK)
//
// In the first case, 'wakenUp' is set to true and the
// following 'selector.select(...)' will wake up immediately.
// Until 'wakenUp' is set to false again in the next round,
// 'wakenUp.compareAndSet(false, true)' will fail, and therefore
// any attempt to wake up the Selector will fail, too, causing
// the following 'selector.select(...)' call to block
// unnecessarily.
//
// To fix this problem, we wake up the selector again if wakenUp
// is true immediately after selector.select(...).
// It is inefficient in that it wakes up the selector for both
// the first case (BAD - wake-up required) and the second case
// (OK - no wake-up required). if (wakenUp.get()) {
selector.wakeup();
}
// fall through
default:
}
} catch (IOException e) {
// If we receive an IOException here its because the Selector is messed up. Let's rebuild
// the selector and retry. https://github.com/netty/netty/issues/8566
rebuildSelector0();
handleLoopException(e);
continue;
} cancelledKeys = 0;
needsToSelectAgain = false;
final int ioRatio = this.ioRatio;
if (ioRatio == 100) {
try {
processSelectedKeys();
} finally {
// Ensure we always run tasks.
runAllTasks();
}
} else {
final long ioStartTime = System.nanoTime();
try {
processSelectedKeys();
} finally {
// Ensure we always run tasks.
final long ioTime = System.nanoTime() - ioStartTime;
runAllTasks(ioTime * (100 - ioRatio) / ioRatio);
}
}
} catch (Throwable t) {
handleLoopException(t);
}
// Always handle shutdown even if the loop processing threw an exception.
try {
if (isShuttingDown()) {
closeAll();
if (confirmShutdown()) {
return;
}
}
} catch (Throwable t) {
handleLoopException(t);
}
}
}

我只想做的更好,仅此而已

Netty怎么切换三种I/O模式和源码解释的更多相关文章

  1. Netty中的三种Reactor(反应堆)

    目录: Reactor(反应堆)和Proactor(前摄器) <I/O模型之三:两种高性能 I/O 设计模式 Reactor 和 Proactor> <[转]第8章 前摄器(Proa ...

  2. Redis三种集群模式介绍

    三种集群模式 redis有三种集群模式,其中主从是最常见的模式. Sentinel 哨兵模式是为了弥补主从复制集群中主机宕机后,主备切换的复杂性而演变出来的.哨兵顾名思义,就是用来监控的,主要作用就是 ...

  3. 简单区分VMware的三种网络连接模式(bridged、NAT、host-only)

    艺搜简介 VMware在安装时默认安装了两块虚拟网卡,VMnet1和VMnet8,另外还有VMnet0.这些虚拟网卡的配置都是由Vmware虚拟机自动生成的,一般来说不需要用户自行设置. Vmware ...

  4. VMware虚拟系统 bridged、NAT、host-only三种网络连接模式

    目录 前言 bridged(桥接模式) NAT(网络地址转换模式) host-only(仅主机模式) 总结 前言 如果你想利用VMWare安装虚拟机,或想创建一个与网内其他机器相隔离的虚拟系统,进行特 ...

  5. vmware为我们提供了三种网络工作模式,它们分别是:Bridged(桥接模式)、NAT(网络地址转换模式)、Host-Only(仅主机模式)。

    原文来自http://note.youdao.com/share/web/file.html?id=236896997b6ffbaa8e0d92eacd13abbf&type=note 我怕链 ...

  6. VMware下三种网络连接模式

    VMware下三种网络连接模式 Bridged(桥接模式) 在桥接模式下,VMware虚拟出来的操作系统就像是局域网中的一独立的主机,它可以访问该类网段内任何一台机器. 桥接网络环境下需要做到: 手动 ...

  7. VMWare中三种网络连接模式的区别

    VMWare中有桥接.NAT.host-only三种网络连接模式,在搭建伪分布式集群时,需要对集群的网络连接进行配置,而这一操作的前提是理解这三种网络模式的区别. 参考以下两篇文章可以更好的理解: V ...

  8. android Service Activity三种交互方式(付源码)(转)

    android Service Activity三种交互方式(付源码) Android应用服务器OSBeanthread  android Service Binder交互通信实例 最下边有源代码: ...

  9. Go语言备忘录:net/http包的使用模式和源码解析

    本文是晚辈对net/http包的一点浅显的理解,文中如有错误的地方请前辈们指出,以免误导! 转摘本文也请注明出处:Go语言备忘录:net/http包的使用模式和源码解析,多谢!  目录: 一.http ...

随机推荐

  1. NSObject和反射2

    NSObject和反射2. commend +R  run id stu=[Student student]; // –>   Student *stu=[Student student]; : ...

  2. 泛目录程序(莲花泛目录程序/黑帽SEO/寄生虫/莲花泛目录解析/泛目录软件)

    莲花泛目录程序强大之处: 1.内容分类详细2.自动推送URL链接3.内置超强原创内容功能系统,页面深受百度搜索引擎喜爱.4.蜘蛛触发繁殖:蜘蛛触发程序任何页面,程序自动生成独立页面并引导繁殖.5.操作 ...

  3. 简述JAVA类的生命周期

    介绍 一个java类的完整的生命周期会经历加载.连接.初始化.使用.和卸载五个阶段: 加载 主要是:把类的信息加载到方法区中,并在堆中实例化一个Class对象. 加载方式 根据类的全路径加载class ...

  4. Ajax传递复杂对象报415

    特别提示:本人博客部分有参考网络其他博客,但均是本人亲手编写过并验证通过.如发现博客有错误,请及时提出以免误导其他人,谢谢!欢迎转载,但记得标明文章出处:http://www.cnblogs.com/ ...

  5. koa 项目实战(七)登录接口

    1.登录接口 /** * @route POST api/users/login * @desc 登录接口地址 * @access 接口是公开的 */ router.post('/login', as ...

  6. DOS 获取硬盘序列号

    DOS命令行操作: 使用diskpart命令,Win+R键运行cmd,进入命令行界面:       1.diskpart       2.list disk 查看有几块硬盘       3.selec ...

  7. PHP AJAX 返回XML数据

    例子:利用AJAX间接访问数据库,查出Nation表中的数据,返回XML数据,并将Nation表中的数据显示在下拉列表框中 外层建一个下拉列表框 </select> JQurey代码 $( ...

  8. k8s应用01-----入门实例

    安装一个单机版的K8S 1.关闭防火墙firewalld2.安装etcd和kubernetesyum install -y etcd kubernetes(会自动安装docker)3.修改配置文件修改 ...

  9. zabbix监控nginx+php-fpm,mysql+主从复制+高可用,tomcat,redis web状态

    zabbix监控对象区分 使用SNMP监控交换 使用IPMI监控服务器硬件 使用Agent监控服务器 使用JMX监控JAVA SNMP监控流程 交换机上开启snmp 在zabbix上添加监控(设置SN ...

  10. 安装nodejs 后运行 npm 命令无响应

    安装和卸载过nodejs, 也编辑过 C:\Users\{账户}\下的.npmrc文件. 再全新安装nodejs ,运行npm 命令,无响应. 处理方法,删除C:\Users\{账户}\下的.npmr ...