Java中BIO和NIO
同步/异步、阻塞/非阻塞概念
同步异步
同步和异步关注的是消息通信机制 (synchronous communication/ asynchronous communication)
同步:在发出一个调用时,在没有得到结果之前,该调用就不返回。一旦调用返回,就得到返回值了。调用者主动等待这个调用的结果。
异步:调用在发出之后就直接返回了,没有立刻得到返回结果。在调用发出后,被调用者通过状态、通知来通知调用者,或通过回调函数处理这个调用。
I/O
通常来说,IO操作包括:对硬盘的读写、对socket的读写以及外设的读写,并且需要进行用户空间和内核空
间的区分(用户空间就是普通的用户进程,内核空间就是内核进程,只有内核空间才可以直接范围磁盘等物理
I/O设备)
用户空间产生一个读请求,请求再转交由内核空间执行
1. 内核检查读取的数据是否就绪
2. 如果就绪,内核将数据从内核空间复制到用户空间(内存上拷贝)
阻塞I/O与非阻塞I/O
阻塞I/O:内核在检查数据未就绪时,会一直等待,直到数据就绪
非阻塞I/O:如果数据没有就绪,则会返回一个标志信息告知用户线程当前要读的数据没有就绪
它们的区别在于I/O的第一阶段,阻塞是选择等待,非阻塞是返回一个标志信息
那么非阻塞I/O的优势在哪里呢?使用阻塞I/O处理网络连接时,有10000个连接就要开10000个线程,无论
有没有数据到来,处理某一连接的线程必须“忠实地阻塞”。而非阻塞I/O就不需要这样,它可以维护一个1000
个线程的线程池,当有数据就绪时,启动一个线程去接受数据,当没有数据时,线程不需要等待,直接就可以
回到池中,等待被调度到去接受其它连接。因此非阻塞I/O非常适合连接多但传输的数据内容不大的情况,如
果连接少数据多,阻塞I/O更容易编程
同步I/O和异步I/O
事实上,同步IO和异步IO模型是针对用户线程和内核的交互来说的,即数据是否就绪的消息传递机制
同步IO:当用户发出IO请求操作之后,如果数据没有就绪,需要通过用户线程或者内核不断地去轮询数据是否
就绪,当数据就绪时,再将数据从内核拷贝到用户线程
异步IO:只有IO请求操作的发出是由用户线程来进行的,内核自动完成检查数据是否就绪和将数据拷贝
到用户空间的过程,然后发送通知告知用户线程IO操作已经完成。
BIO、NIO、AIO
BIO:同步阻塞式IO,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。
NIO:同步非阻塞式IO,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。
AIO(NIO.2): 异步非阻塞IO,在此种模式下,用户进程只需要发起一个IO操作然后立即返回,等IO操作真正的完成以后,应用程序会得到IO操作完成的通知,此时用户进程只需要对数据进行处理就好了,不需要进行实际的IO读写操作,因为真正的IO读取或者写入操作已经由内核完成了。
BIO
阻塞IO,一个请求对应一个线程,线程是阻塞的。

缺点:
阻塞式IO、弹性伸缩能力强、多线程消耗资源。
NIO
每个客户端请求都会注册到Selector(多路复用器)

优点:
非阻塞式IO模型、弹性伸缩能力强、单线陈节省资源。

同步非阻塞式IO,关键是采用了事件驱动的思想来实现了一个多路转换器。
NIO与BIO最大的区别就是只需要开启一个线程就可以处理来自多个客户端的IO事件,实现原理就是多路复用器,可以监听来自多个客户端的IO事件:
A. 若服务端监听到客户端连接请求,便为其建立通信套接字(java中就是通道),然后返回继续监听,若同时有多个客户端连接请求到来也可以全部收到,依次为它们都建立通信套接字。
B. 若服务端监听到来自已经创建了通信套接字的客户端发送来的数据,就会调用对应接口处理接收到的数据,若同时有多个客户端发来数据也可以依次进行处理。
C. 监听多个客户端的连接请求和接收数据请求同时还能监听自己是否有数据要发送。
总之就是在一个线程中就可以调用多路复用接口(java中是select)阻塞同时监听来自多个客户端的IO请求,一旦有收到IO请求就调用对应函数处理。
一旦有请求到来(不管是几个同时到还是只有一个到),都会调用对应IO处理函数处理,所以:
(1)NIO适合处理连接数目特别多,但是连接比较短(轻操作)的场景,Jetty,Mina,ZooKeeper等都是基于java nio实现。
(2)BIO方式适用于连接数目比较小且固定的场景,这种方式对服务器资源要求比较高,并发局限于应用中。
Java的NIO代码
相关链接:java的socket编程(BIO)
this.selector.select(); 在这里会阻塞,无论是客户端连接还是客户端发送数据还是客户端关闭,这里都会触发。虽然这里是单线程,但是底层处理用到了线程池。
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator; /**
* 阻塞点this.selector.select();
* 轮询器虽然是一个线程内部也是线程池
*/
public class NioSocket {
private Selector selector; //通道管理器(管理器) /**
* 初始化Channel并绑定端口
* @param port
* @throws IOException
*/
public void initServer(int port) throws IOException {
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false); //非阻塞
serverChannel.socket().bind(new InetSocketAddress(port)); this.selector = Selector.open();
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("服务器已启动...");
} /**
* 监听轮询器
* @throws IOException
*/
public void listenSelector() throws IOException {
//轮询监听selector
while (true){
//等待客户连接
//select模型,多路复用
//this.selector.select(); //在这里会阻塞,无论是连接还是客户端发送数据还是客户端关闭,这里都会触发
this.selector.selectNow(); //这里不阻塞会立即执行
Iterator<SelectionKey> iteKey = this.selector.selectedKeys().iterator();
while (iteKey.hasNext()){
SelectionKey key = iteKey.next();
iteKey.remove(); //移除,防止重复处理
//处理请求
handler(key);
}
}
} /**
* 处理客户端请求
* @param key
*/
private void handler(SelectionKey key) throws IOException {
if (key.isAcceptable()){ //处理连接请求
//处理客户端连接请求事件
ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
SocketChannel socketChannel = serverChannel.accept();
//接受客户端发送的信息时,需要给通道设置读权限
socketChannel.configureBlocking(false);
socketChannel.register(selector,SelectionKey.OP_READ);
}else if(key.isReadable()){ //处理读请求
//处理读事件
SocketChannel socketChannel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int readData = socketChannel.read(buffer);
if (readData>0){
String info = new String(buffer.array(),"GBK").trim();
System.out.println("服务端收到数据: "+Thread.currentThread()+info);
}else {
System.out.println("客户端关闭了...");
key.cancel();
}
}
} public static void main(String[] args) throws IOException {
NioSocket nio = new NioSocket();
nio.initServer(8888);
nio.listenSelector();
}
}

参考
http://m.elecfans.com/article/632834.html
https://www.cnblogs.com/IUbanana/p/7245980.html
Java中BIO和NIO的更多相关文章
- Java中BIO,NIO,AIO的理解
在高性能的I/O体系设计中,有几个概念常常会使我们感到迷惑不解.具体如下: 1 什么是同步? 2 什么是异步? 3 什么是阻塞? 4 什么是非阻塞? 5 什么是同步阻塞? 6 什么是同步非阻塞? 7 ...
- Java中BIO、NIO、AIO的区别和应用场景
学习IO,首先要明白四个东西. 1.同步 java自己去处理io. 2.异步 java将io交给操作系统去处理,告诉缓存区大小,处理完成回调. 3.阻塞 ...
- Java的BIO和NIO很难懂?用代码实践给你看,再不懂我转行!
本文原题“从实践角度重新理解BIO和NIO”,原文由Object分享,为了更好的内容表现力,收录时有改动. 1.引言 这段时间自己在看一些Java中BIO和NIO之类的东西,也看了很多博客,发现各种关 ...
- JAVA 中BIO,NIO,AIO的理解
[转自]http://qindongliang.iteye.com/blog/2018539 ?????????????????????在高性能的IO体系设计中,有几个名词概念常常会使我们感到迷惑不解 ...
- JAVA 中BIO,NIO,AIO的理解以及 同步 异步 阻塞 非阻塞
在高性能的IO体系设计中,有几个名词概念常常会使我们感到迷惑不解.具体如下: 序号 问题 1 什么是同步? 2 什么是异步? 3 什么是阻塞? 4 什么是非阻塞? 5 什么是同步阻塞? 6 什么是同步 ...
- JAVA 中BIO,NIO,AIO的理解 (转)
转自: http://qindongliang.iteye.com/blog/2018539 另外类似可参考资料 :http://www.360doc.com/content/13/1029/20/9 ...
- Java中BIO,NIO,AIO的理解
在高性能的IO体系设计中,有几个名词概念常常会使我们感到迷惑不解.具体如下: 1 什么是同步? 2 什么是异步? 3 什么是阻塞? 4 什么是非阻塞? 5 什么是同步阻塞? 6 什么是同步非阻塞? 7 ...
- Java的BIO,NIO,AIO
Java中的IO操作可谓常见.在Java的IO体系中,常有些名词容易让人困惑不解.为此,先通俗地介绍下这些名词. 1 什么是同步? 2 什么是异步? 3 什么是阻塞? 4 什么是非阻塞? 5 什么是同 ...
- 【Java】 BIO与NIO以及AIO分析
一.BIO与NIO以及AIO的概念 BIO是同步阻塞式的IO NIO是同步非阻塞的IO (NIO1.0,JDK1.4) AIO是非同步非阻塞的IO(NIO2.0,JDK1.7) 二.BIO简单分析 1 ...
随机推荐
- vue-route开发注意事项
1.router-link to 动态赋值 router-link组件的to属性值有两种写法,字符串类型和对象类型 如果要动态传值,比如放到for循环中,传入for的index值,这时就必须使用对象形 ...
- Docker部署web项目-war包
一.部署springmvc(war包)项目 1.手工方式 ①搜索tomcat镜像 docker search tomcat ②拉取tomcat基础镜像至本地仓库 docker pull tomcat ...
- 网络公开课和MOOC资源
美国(USA) 1. 麻省理工学院开放课程(Free Online Course Materials/ MIT OpenCourseWare) 2. 耶鲁大学开放课程(Online Video Lec ...
- Laya微信小游戏的动态资源
版本2.1.1. 由于有4m包限制,所以一般小游戏项目分成主包+远程资源. 现在我新建一个remote目录,该目录下资源不发布到微信小游戏目录下,而是服务器远程加载. 发布时,勾线是否提取本地包 远程 ...
- Excel如何输入负数
一般红字发票很少开,以前都是单独把红字发票摘出来放到一行里,然后加减一下,前段时间有个客户因为普票无法报销,改要了专票,因为是电子发票,无法作废,开了张红字.虽然红字很少开,但是想着百度一下如何在ex ...
- [LeetCode] 1. Two Sum 两数和
Given an array of integers, return indices of the two numbers such that they add up to a specific ta ...
- [LeetCode] 117. Populating Next Right Pointers in Each Node II 每个节点的右向指针 II
Follow up for problem "Populating Next Right Pointers in Each Node". What if the given tre ...
- WIN7 浏览器 收藏夹栏字体太小
在“窗口颜色和外观”-项目-“消息框”,把字体大小调大. "标题按钮" 大小 21.
- Bat批处理之for/f详解
转自:https://www.cnblogs.com/zhangq/p/3988697.html 含有/F的for格式: FOR /F ["options"] %%i IN (fi ...
- 【神经网络与深度学习】【计算机视觉】Fast R-CNN
转自:https://zhuanlan.zhihu.com/p/24780395?refer=xiaoleimlnote 首先声明:本文很多内容来自两个博客: RCNN, Fast-RCNN, Fas ...