参考文献:极客时间傅健老师的《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. oracle的事务

    一.事务 保证数据的一致性,有一组相关的dml语句组成,该组的dml语句要么全部成功,要么全部失败 如:网上转账就是典型的要用事物来处理,用以保证数据的一致性 二.事务和锁 当执行事物操作时(dml语 ...

  2. Java字节码例子解析

    举个简单的例子: public class Hello {     public static void main(String[] args) {         String string1 = ...

  3. IntelliJ IDEA利用Maven下载所需的JAR包到项目中

    直接复制JetBrains/../conf/settings.xml后修改镜像出现问题,然后用了这里的settings.xml配置文件.

  4. 转载:在Excel中将数据库字段转换成驼峰式

    转载地址 在Excel中将数据库字段转换成驼峰式 1.将数据库字段复制到Excel表格第一列: 2.在第二列顶部输入=PROPER(A1)命令: 3.在第三列顶部输入=SUBSTITUTE(B1,&q ...

  5. 2018-2019-2 20165330《网络对抗技术》Exp8 Web基础

    目录 基础问题 相关知识 实验内容 实验步骤 实验总结与体会 实验内容 Web前端HTML 能正常安装.启停Apache.理解HTML,理解表单,理解GET与POST方法,编写一个含有表单的HTML ...

  6. 第11组 Alpha冲刺(2/6)

    第11组 Alpha冲刺(2/6)   队名 不知道叫什么团队 组长博客 https://www.cnblogs.com/xxylac/p/11860949.html 作业博客 https://edu ...

  7. vga转HDMI与hdmi转VGA区别

  8. 中间件 | Nginx实现动静分离

    Nginx动静分离基本概述 动静分离,通过中间件将动静分离和静态请求进行分离: 通过中间件将动态请求和静态请求分离,可以建上不必要的请求消耗,同事能减少请求的延时. 通过中间件将动态请求和静态请求分离 ...

  9. 前端知识点回顾之重点篇——ES6的Iterator和Generator

    Iterator 迭代器是一种接口.是一种机制. 为各种不同的数据结构提供统一的访问机制.任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员). Iter ...

  10. CentOS7 源码安装 PostgreSQL 12

    PostgreSQL 12 源码安装 Table of Contents 1. 下载 2. 准备环境 3. 编译安装 4. 设置环境变量 5. 初始化数据库 6. 配置参数文件 6.1. postgr ...