I/O读写的另一种方式-NIO
我们知道,系统运行的性能瓶颈通常在I/O读写,包括对端口和文件的操作上,过去,在打开一个I/O通道后,read()将一直等待在端口一边读取字节内容,如果没有内容进来,read()也是傻傻的等,这会影响我们程序继续做其他事情,那么改进做法就是开设线程,让线程去等待,但是这样做也是相当耗费资源的。
一、BIO带来的挑战
BIO即阻塞I/O,不管是磁盘I/O还是网络I/O,数据在写入OutputStream或者从InputStream读取时都有可能会阻塞,一旦阻塞,线程将会失去CPU的使用权,这在当前的大规模访问量和有性能要求的情况下是不能被接收的。虽然当前的网络I/O有一些解决办法,如一个客户端一个处理线程,出现阻塞时只是一个线程阻塞而不会影响其他线程工作,还有为了减少系统线程的开销,采用线程池的办法来减少线程创建和回收的成本,但是有一些使用场景下仍然是无法解决的。如当前的一些需要大量HTTP长连接的情况。即使线程的数量不是问题,仍然有一些问题是无法避免的,比如我们想给某些客户端更高的服务优先级,很难通过设计线程的优先级来完成。
二、NIO的工作方式
下图为NIO的相关类图:
其中有两个关键类:Channel和Selector,它们是NIO中的核心概念。
Channel:通道
Selector:这个类似一个观察者,只要我们把需要探知的socketchannel告诉Selector,我们接着做别的事情,当有事件发生时,他会通知我们,传回一组SelectionKey,我们读取这些Key,就会获得我们刚刚注册过的socketchannel,然后,我们从这个Channel中读取数据,放心,包准能够读到,接着我们可以处理这些数据。
Selector内部原理实际是在做一个对所注册的channel的轮询访问,不断的轮询(目前就这一个算法),一旦轮询到一个channel有所注册的事情发生,比如数据来了,他就会站起来报告,交出一把钥匙,让我们通过这把钥匙来读取这个channel的内容。
三、基于NIO的Socket请求的处理过程
四、代码示例
public void selector() throws IOException {
ByteBuffer buffer = ByteBuffer.allocate(1024);
Selector selector = Selector.open();
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);//设置为非阻塞方式
ssc.socket().bind(new InetSocketAddress(8080));
ssc.register(selector,SelectionKey.OP_ACCEPT);//注册监听事件
while (true){
Set selectedKeys = selector.selectedKeys();//取得所有KEY集合
Iterator it = selectedKeys.iterator();
while(it.hasNext()){
SelectionKey key = (SelectionKey) it.next();
if((key.readyOps() & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT){
ServerSocketChannel ssChannel = (ServerSocketChannel)key.channel();
SocketChannel sc = ssChannel.accept();//接收到服务端的请求
sc.configureBlocking(false);
sc.register(selector,SelectionKey.OP_READ);
it.remove();
}else if((key.readyOps() & SelectionKey.OP_READ)==SelectionKey.OP_READ){
SocketChannel sc = (SocketChannel)key.channel();
while(true){
buffer.clear();
int n = sc.read(buffer);//读取数据
if(n<=0){
break;
}
buffer.flip();
}
it.remove();
}
}
}
}
转载于:https://blog.51cto.com/yuke198907/1340766
I/O读写的另一种方式-NIO相关推荐
- 最近总结了串口(COM)读写操作的三种方式
最近总结了串口(COM)读写操作的三种方式: 第1种方式是采用微软在.NET2.0推出了一个串口控件,SerialPort类,但必须是.NET2.0才可以 第2种方式是用API写串口通信,虽然难度高, ...
- Spark读写Hbase的二种方式对比
作者:Syn良子 出处:http://www.cnblogs.com/cssdongl 转载请注明出处 一.传统方式 这种方式就是常用的TableInputFormat和TableOutputForm ...
- QT读写Sqlite数据库三种方式
QT对一些基本的数据库的访问封装,可谓是极大的方便的我们开发人员,现在我们就来说下QT对Sqlite这个数据库的读写,Sqlite是一个比较小型的本地数据库,对于保存一些软件配置参数或量不是很大的数据 ...
- spark sql hbase java_Spark 读写 HBase 的两种方式(RDD、DataFrame)
使用 saveAsHadoopDataset 写入数据 import org.apache.hadoop.hbase.{HBaseConfiguration, HTableDescriptor, Ta ...
- golang 读写文件的四种方式
读文件 读取的文件放在file/test:也就是file包下的test这个文件,里面写多一点文件 读文件方式一:利用ioutil.ReadFile直接从文件读取到[]byte中 func Read0( ...
- 用CSV文件读写数据的两种方式(转)
导读:有时候我们需要对收集的数据做统计,并在页面提供显示以及下载.除了对传统的excel存取之外,对CSV文件的存取也很重要.本文列出了这两种操作的详细代码. 代码: <?php $file = ...
- Qt读写文件(2种方式)实现详解
文件的读写是很多应用程序具有的功能,甚至某些应用程序就是围绕着某一种格式文件的处 理而开发的,所以文件读写是应用程序开发的一个基本功能. 文本文件是指以纯文本格式存储的文件,例如用 Qt Creato ...
- Java读写文件的几种方式
前言 Java中读写文件是非常基本的IO操作了,现在总结一下常见的用法.首先总结一下读取文件的步骤: 根据文件的路径获取到文件File对象 将File对象转换成输入流InputStream 将输入流读 ...
- golang读写文件的几种方式
golang中处理文件有很多种方式,下面我们来看看. (1)使用os模块 先来看看如何查看文件属性 package mainimport ("fmt""os" ...
最新文章
- 大规模业务服务器开发总结
- 《Java入门经典(第7版)》—— 6.11 练习
- Windows2003 IIS6.0启用Gzip功能
- 如何用vue-router为每个路由配置各自的title
- c语言数组在栈上的分配,彻底弄懂为什么不能把栈上分配的数组(字符串)作为返回值...
- Web服务(Apache、Nginx、Tomcat、Jetty)与应用(LAMP、CMS-WordPressGhost、Jenkins、Gitlab)
- 带有Flask的服务器端DataTable
- java文本区水平对齐方式,如何将文本居中在水平StackLayout中?
- 全网最细JAVA窗口背景图片设置
- JavaWeb在线聊天系统开发
- ENVI执行监督分类后分类结果背景也被分类了的解决方案
- NEO主要技术社区成员大曝光
- 第7章,广义相加模型(GAMs)
- 基于pam实现的批量执行命令工具-Cyberark
- CityEngine2018正版免费申请试用教程
- 为何一些人认为从事 IT 行业的人是屌丝男?
- 2345加速浏览器有哪些特点
- 基于S32DS实现CAN、LIN基础结合芯片UJA1075的功耗模式切换设置(Standby、Normal、Sleep)
- 转:C语言面试题大汇总 (图像处理方向)
- 【Basic Use Case】
热门文章
- 8.1 Ext JS应用测试概览
- 网页爬虫,HttpClient+Jericho HTML Parser 实现网页的抓取
- linux java gc_Java GC机制及相关
- sql如何取前几行_重磅!蚂蚁金服开源机器学习工具SQLFlow,机器学习比SQL还简单...
- centos7 安装 mysql8 强制修改密码
- Spring Cloud基础入门
- 用python画的基本知识_Opencv-python画图基础知识
- java 创建bean_java – 使用spring按需创建bean
- mysql数据库一列多值查询
- git分支添加访问权限