温故知新-java的I/O模型-BIO&NIO&AIO
- Posted by 微博@Yangsc_o
- 原创文章,版权声明:自由转载-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0
摘要
通过温故知新-快速理解Linux网络IO的回顾,我们了解Linux下网络编程的5种I/O模型&I/O多路复用,接下来回顾一下java中的I/O模型,包括BIO、NIO、AIO,为下一篇netty做铺垫。
传统的BIO编程
传统的BIO通信模型
问题
- 该模型最大的问题就是,客户端的线程个数和客户端的并发呈1:1的关系,线程切换将满满拖垮整个系统;
- 测试代码如下
---------- server ----------
@Log4j2
public class BioServer {
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(9090);
while (true) {
log.info("-- serverSocket before accept --");
Socket socket = serverSocket.accept();
log.info("-- serverSocket end accept --");
new Thread(() -> {
try {
// 读内容
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String readLine = bufferedReader.readLine();
log.info("thread:{} client :{}", Thread.currentThread().getName(), readLine);
} catch (IOException e) {
log.error(e);
}
}).run();
}
}
}
---------- client ----------
@Log4j2
public class BioClient {
public static void main(String[] args) throws Exception {
for (int i = 0; i < 10; i++) {
Integer tmp = i;
new Thread(() -> {
try {
Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 9090);
OutputStream outputStream = socket.getOutputStream();
PrintWriter printWriter = new PrintWriter(outputStream);
printWriter.write("client message index: " + tmp);
printWriter.flush();
log.info("index:{}", tmp);
} catch (Exception e) {
log.error(e);
}
}).run();
}
}
}
伪异步I/O编程
- 为了解决线程耗尽的问题,引入了线程池,没本质区别;
NIO编程
NIO库是在JDK1.4引进的,弥补了原来同步阻塞I/O的不足,先看一下通信模型,直观的感受一下;
先了解三个概念:缓冲区(buffer)、通道(channel)、多路复用器(Selector)
- 缓冲区(buffer)
在NIO厍中,所有数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中的; 在写入数据时,写入到缓冲区中。任何时候访问NIO中的数据,都是通过缓冲区进行操作。
类型的缓存有很多种,eg:
- 通道(channel)
channel是一个通道,网络数据通过channel读取和写入;通道是双向的,流是单项的,流只是在一个方向移动(输入、输出),通道是双工的,可以同时读写,这个跟Unix TCP socket也是一致的;
- Selector
- 从上面的图中,最重要的就是Selector,这就是java实现I/O多路复用的核心;
- 一个Selector可以轮询多个注册到Selector的channel,如果某一个channel发送读写事件,channel就处于了就绪状态,就会被Selector轮询出来,然后通过SelectionKey获取就是Channel就绪集合,由于JDK使用了epoll()代替了传统的select轮询,所以没有1024的句柄限制。
- 跟BIO和伪异步IO相比,只用一个线程负责轮询,就可以接入成千上完的客户端,所以打好基础建设多么的重要!!
- 流程
- 测试代码
--------- server -----
@Log4j2
public class NioServer {
public static void main(String[] args) throws Exception {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(9090));
serverSocketChannel.configureBlocking(false);
Selector selector = Selector.open();
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
new Thread(() -> {
try {
while (true) {
if (selector.select(1) > 0) {
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> it = selectedKeys.iterator();
SelectionKey key = null;
while (it.hasNext()) {
key = it.next();
try {
handle(key, selector);
} catch (Exception e) {
if (key != null) {
key.cancel();
if (key.channel() != null) {
key.channel().close();
}
}
} finally {
it.remove();
}
}
}
}
} catch (Throwable t) {
t.printStackTrace();
}
}).start();
}
private static void handle(SelectionKey key, Selector selector) throws IOException {
if (key.isValid()) {
// 处理新接入的请求消息
if (key.isAcceptable()) {
log.info("new channel ...");
// Accept the new connection
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
SocketChannel sc = ssc.accept();
sc.configureBlocking(false);
// Add the new connection to the selector
sc.register(selector, SelectionKey.OP_READ);
}
if (key.isReadable()) {
// Read the data
SocketChannel sc = (SocketChannel) key.channel();
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
int readBytes = sc.read(readBuffer);
if (readBytes > 0) {
readBuffer.flip();
byte[] bytes = new byte[readBuffer.remaining()];
readBuffer.get(bytes);
String data = new String(bytes, "UTF-8");
log.info("data:{}", data);
} else if (readBytes < 0) {
// 对端链路关闭
key.cancel();
sc.close();
}
}
}
}
}
AIO编程
NIO 2.0引入了新的异步通的概念,提供了异步文件通道和异步套接字通道的实现。
- 通过juc的Future表示异步操作的结果
- 在执行异步操作时传入channels
- CompletionHandler接口实现类作为操作完成的回调。
它是真正的异步非阻塞的IO模型,对应UNIX网络编程重的事件驱动I/O,不需要Selector对注册的通道进行轮询。
- 测试代码
@Log4j2
public class AioServer {
public static void main(String[] args) throws Exception {
AsynchronousServerSocketChannel channel = AsynchronousServerSocketChannel
.open();
channel.bind(new InetSocketAddress(9090));
channel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {
@Override
public void completed(final AsynchronousSocketChannel asynchronousSocketChannel, Void attachment) {
channel.accept(null, this);
ByteBuffer buffer = ByteBuffer.allocate(1024);
asynchronousSocketChannel.read(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result_num, ByteBuffer attachment) {
attachment.flip();
CharBuffer charBuffer = CharBuffer.allocate(1024);
CharsetDecoder decoder = Charset.defaultCharset().newDecoder();
decoder.decode(attachment, charBuffer, false);
charBuffer.flip();
String data = new String(charBuffer.array(), 0, charBuffer.limit());
log.info("data:{}", data);
try {
asynchronousSocketChannel.close();
} catch (Exception e) {
log.info(e);
}
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
log.info("read error");
}
});
}
@Override
public void failed(Throwable exc, Void attachment) {
System.out.println("accept error");
}
});
while (true){
Thread.sleep(1000);
}
}
}
几种IO模型的对比
netty
- 下一篇就轮到!
参考
-《Netty 权威指南》第二版 – 李林峰
-《netty实战》–何品
你的鼓励也是我创作的动力
温故知新-java的I/O模型-BIO&NIO&AIO的更多相关文章
- JAVA-IO模型(BIO,NIO,AIO)
基本概念 阻塞和非阻塞 阻塞是进行读写时, 如果当时没有东西可读,或者暂时不可写, 程序就进入等待, 直到有东西可读或者可写为止 非阻塞是如果没有东西可读, 或者不可写, 读写函数马上返回, 而不会等 ...
- (转)也谈BIO | NIO | AIO (Java版)
原文地址: https://my.oschina.net/bluesky0leon/blog/132361 关于BIO | NIO | AIO的讨论一直存在,有时候也很容易让人混淆,就我的理解,给出一 ...
- 也谈BIO | NIO | AIO (Java版--转)
关于BIO | NIO | AIO的讨论一直存在,有时候也很容易让人混淆,就我的理解,给出一个解释: BIO | NIO | AIO,本身的描述都是在Java语言的基础上的.而描述IO,我们需要从两个 ...
- I/O模型系列之三:IO通信模型BIO NIO AIO
一.传统的BIO 网络编程的基本模型是Client/Server模型,也就是两个进程之间进行相互通信,其中服务端提供位置信息(绑定的IP地址和监听端口),客户端通过连接操作向服务端监听的地址发起连接请 ...
- java BIO/NIO/AIO 学习
一.了解Unix网络编程5种I/O模型 1.1.阻塞式I/O模型 阻塞I/O(blocking I/O)模型,进程调用recvfrom,其系统调用直到数据报到达且被拷贝到应用进程的缓冲区中或者发生错误 ...
- Java提供了哪些IO方式?IO, BIO, NIO, AIO是什么?
IO一直是软件开发中的核心部分之一,而随着互联网技术的提高,IO的重要性也越来越重.纵观开发界,能够巧妙运用IO,不但对于公司,而且对于开发人员都非常的重要.Java的IO机制也是一直在不断的完善,以 ...
- 3. 彤哥说netty系列之Java BIO NIO AIO进化史
你好,我是彤哥,本篇是netty系列的第三篇. 欢迎来我的公从号彤哥读源码系统地学习源码&架构的知识. 简介 上一章我们介绍了IO的五种模型,实际上Java只支持其中的三种,即BIO/NIO/ ...
- JAVA中的BIO,NIO,AIO
在了解BIO,NIO,AIO之前先了解一下IO的几个概念: 1.同步 用户进程触发IO操作并等待或者轮询的去查看IO操作是否就绪, 例如自己亲自出马持银行卡到银行取钱 2.异步 用户触发IO操作以后, ...
- BIO | NIO | AIO (Java版)
几篇解释的不错的文章: BIO NIO AIO NIO.2 入门,第 1 部分: 异步通道 API 使用异步 I/O 大大提高应用程序的性能
随机推荐
- 基于 abp vNext 和 .NET Core 开发博客项目 - 自定义仓储之增删改查
上一篇文章(https://www.cnblogs.com/meowv/p/12913676.html)我们用Code-First的方式创建了博客所需的实体类,生成了数据库表,完成了对EF Core的 ...
- spark机器学习从0到1决策树(六)
一.概念 决策树及其集合是分类和回归的机器学习任务的流行方法. 决策树被广泛使用,因为它们易于解释,处理分类特征,扩展到多类分类设置,不需要特征缩放,并且能够捕获非线性和特征交互. 诸如随机森林和 ...
- Reflux之Store
Reflux中的Store既是一个listener(既有对action的监听,又有对store的监听)同时又是一个publisher. 一.监听单个action const Reflux = requ ...
- 如何使用IDEA快速创建一个springboot项目
如何使用IDEA快速创建一个springboot项目 https://jingyan.baidu.com/article/0964eca24fdd938284f53640.html
- 201771010128 王玉兰《面象对象程序设计(Java)》第六周学习总结
第一部分:基础知识总结: 1.继承 A:用已有类来构建新类的一种机制,当定义了一个新类继承一个类时,这个新类就继承了这个类的方法和域以适应新的情况: B:特点:具有层次结构.子类继承父类的方法和域: ...
- zookeeper实现分布式锁总结,看这一篇足矣(设计模式应用实战)
分布式锁纵观网络各种各样的帖子层出不穷,笔者查阅很多资料发现一个问题,有些文章只写原理并没有具体实现,有些文章虽然写了实现但是并不全面 借这个周末给大家做一个总结,代码拿来就可以用并且每一种实现都经过 ...
- 联通光猫管理员密码分析(HG220GS-U)
联通光猫管理员密码分析 联通光猫型号:HG220GS-U软件版本:E00L3.03 运营商一直在做光猫防破解,对抗升级还是比较快的,所有的分析结论都和版本绑定的,因为运营商或者路由器的开发商看到后可能 ...
- Wilson's theorem在RSA题中运用
引言 最近一段时间在再练习数论相关的密码学题目,自己之前对于数论掌握不是很熟练,借此机会先对数论基本的四大定理进行练习 这次的练习时基于Wilson's theorem(威尔逊定理)在RSA题目中的练 ...
- python 03—字符串分割
字符串分割 例:sentenc = "I am an Englist sentenc" sentence.split() split()把字符串按照空格进行分割,所以得到的结果是 ...
- 一文彻底搞懂BERT
一.什么是BERT? 没错下图中的小黄人就是文本的主角Bert ,而红色的小红人你应该也听过,他就是ELMo.2018年发布的BERT 是一个 NLP 任务的里程碑式模型,它的发布势必会带来一个 NL ...