Netty怎么切换三种I/O模式和源码解释
参考文献:极客时间傅健老师的《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模式和源码解释的更多相关文章
- Netty中的三种Reactor(反应堆)
目录: Reactor(反应堆)和Proactor(前摄器) <I/O模型之三:两种高性能 I/O 设计模式 Reactor 和 Proactor> <[转]第8章 前摄器(Proa ...
- Redis三种集群模式介绍
三种集群模式 redis有三种集群模式,其中主从是最常见的模式. Sentinel 哨兵模式是为了弥补主从复制集群中主机宕机后,主备切换的复杂性而演变出来的.哨兵顾名思义,就是用来监控的,主要作用就是 ...
- 简单区分VMware的三种网络连接模式(bridged、NAT、host-only)
艺搜简介 VMware在安装时默认安装了两块虚拟网卡,VMnet1和VMnet8,另外还有VMnet0.这些虚拟网卡的配置都是由Vmware虚拟机自动生成的,一般来说不需要用户自行设置. Vmware ...
- VMware虚拟系统 bridged、NAT、host-only三种网络连接模式
目录 前言 bridged(桥接模式) NAT(网络地址转换模式) host-only(仅主机模式) 总结 前言 如果你想利用VMWare安装虚拟机,或想创建一个与网内其他机器相隔离的虚拟系统,进行特 ...
- vmware为我们提供了三种网络工作模式,它们分别是:Bridged(桥接模式)、NAT(网络地址转换模式)、Host-Only(仅主机模式)。
原文来自http://note.youdao.com/share/web/file.html?id=236896997b6ffbaa8e0d92eacd13abbf&type=note 我怕链 ...
- VMware下三种网络连接模式
VMware下三种网络连接模式 Bridged(桥接模式) 在桥接模式下,VMware虚拟出来的操作系统就像是局域网中的一独立的主机,它可以访问该类网段内任何一台机器. 桥接网络环境下需要做到: 手动 ...
- VMWare中三种网络连接模式的区别
VMWare中有桥接.NAT.host-only三种网络连接模式,在搭建伪分布式集群时,需要对集群的网络连接进行配置,而这一操作的前提是理解这三种网络模式的区别. 参考以下两篇文章可以更好的理解: V ...
- android Service Activity三种交互方式(付源码)(转)
android Service Activity三种交互方式(付源码) Android应用服务器OSBeanthread android Service Binder交互通信实例 最下边有源代码: ...
- Go语言备忘录:net/http包的使用模式和源码解析
本文是晚辈对net/http包的一点浅显的理解,文中如有错误的地方请前辈们指出,以免误导! 转摘本文也请注明出处:Go语言备忘录:net/http包的使用模式和源码解析,多谢! 目录: 一.http ...
随机推荐
- oracle的事务
一.事务 保证数据的一致性,有一组相关的dml语句组成,该组的dml语句要么全部成功,要么全部失败 如:网上转账就是典型的要用事物来处理,用以保证数据的一致性 二.事务和锁 当执行事物操作时(dml语 ...
- Java字节码例子解析
举个简单的例子: public class Hello { public static void main(String[] args) { String string1 = ...
- IntelliJ IDEA利用Maven下载所需的JAR包到项目中
直接复制JetBrains/../conf/settings.xml后修改镜像出现问题,然后用了这里的settings.xml配置文件.
- 转载:在Excel中将数据库字段转换成驼峰式
转载地址 在Excel中将数据库字段转换成驼峰式 1.将数据库字段复制到Excel表格第一列: 2.在第二列顶部输入=PROPER(A1)命令: 3.在第三列顶部输入=SUBSTITUTE(B1,&q ...
- 2018-2019-2 20165330《网络对抗技术》Exp8 Web基础
目录 基础问题 相关知识 实验内容 实验步骤 实验总结与体会 实验内容 Web前端HTML 能正常安装.启停Apache.理解HTML,理解表单,理解GET与POST方法,编写一个含有表单的HTML ...
- 第11组 Alpha冲刺(2/6)
第11组 Alpha冲刺(2/6) 队名 不知道叫什么团队 组长博客 https://www.cnblogs.com/xxylac/p/11860949.html 作业博客 https://edu ...
- vga转HDMI与hdmi转VGA区别
- 中间件 | Nginx实现动静分离
Nginx动静分离基本概述 动静分离,通过中间件将动静分离和静态请求进行分离: 通过中间件将动态请求和静态请求分离,可以建上不必要的请求消耗,同事能减少请求的延时. 通过中间件将动态请求和静态请求分离 ...
- 前端知识点回顾之重点篇——ES6的Iterator和Generator
Iterator 迭代器是一种接口.是一种机制. 为各种不同的数据结构提供统一的访问机制.任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员). Iter ...
- CentOS7 源码安装 PostgreSQL 12
PostgreSQL 12 源码安装 Table of Contents 1. 下载 2. 准备环境 3. 编译安装 4. 设置环境变量 5. 初始化数据库 6. 配置参数文件 6.1. postgr ...