java nio aio bio概念
title: java nio aio bio概念
date: 2018/1/13 21:12:55
tags: [nio,aio]
categories:
- 开发
- java
就目前来说,大多数的系统瓶颈在io , io的瓶颈又在寻址 ……
跑题了,我先来记录总结几个基本概念吧
IO分两阶段:
1.数据准备阶段
2.内核空间复制回用户进程缓冲区阶段
一般来讲:阻塞IO模型、非阻塞IO模型、IO复用模型(select/poll/epoll)、信号驱动IO模型都属于同步IO,因为阶段2是阻塞的(尽管时间很短)。只有异步IO模型是符合POSIX异步IO操作含义的,不管在阶段1还是阶段2都可以干别的事。
阻塞和非阻塞
是进程访问数据的时候,数据是否准备就绪的一种处理方式 。
当数据没有准备好的时候:
-
阻塞
需要等待数据缓冲区中的数据准备好后,才处理其它事情
-
非阻塞
数据如果没有准备好,直接返回
同步和异步
基于应用程序
和操作系统
处理io事件所采用的方式
-
同步
-
应用程序直接参与io读写的操作
-
会阻塞在某个方法上等待io事件的完成(阻塞io事件 或者 通过轮询方式)
-
阻塞io事件
不能做自己的事情,一直阻塞线程
-
IO事件轮询方式(多路复用,Select模式)
读写事件交给一个单独的(select)线程来处理,并完成io事件的注册功能 ,然后不断的轮询读写缓冲区看数据是否准备好,有数据通知我们的读写线程 。这样以前的读写线程可以做其它事情 ,因为这个时候阻塞的不是所有的io线程,而是select线程 (select 相当于一个管家)
但是它还是同步的,因为真正的io操作不是完全交给操作系统的,应用程序要参与
-
例子(把select比做管家,还有客人和主人):
当【客人】来拜访【主人】的时候,先找到【管家】,【管家】得到这个注册信息后,跟【主人】说:我这里来了一个或者多个【客人】,他们需要【主人】给他们某某东西 。这个时候【客人】可以去做其它事情,比如看看花园 。当【管家】得知【主人】准备好东西后,他就去找对应的某人 告诉这位【客人】主人给他某样东西 ,这个时候阻塞是发生在 【管家】不是【客人】
-
-
-
异步
-
所有的io操作交给OS处理
-
可以去做其它事情,并不需要去完成真正的io操作,当操作系统完成io后,给我们应用程序一个通知就行
-
-
例子(来源于网络)阻塞和非阻塞,同步和异步
故事:老王烧开水。
出场人物:老张,水壶两把(普通水壶,简称水壶;会响的水壶,简称响水壶)。
老王想了想,有好几种等待方式
- 老王用水壶煮水,并且站在那里,不管水开没开,每隔一定时间看看水开了没。-同步阻塞
老王想了想,这种方法不够聪明。
- 老王还是用水壶煮水,不再傻傻的站在那里看水开,跑去寝室上网,但是还是会每隔一段时间过来看看水开了没有,水没有开就走人。-同步非阻塞
老王想了想,现在的方法聪明了些,但是还是不够好。
- 老王这次使用高大上的响水壶来煮水,站在那里,但是不会再每隔一段时间去看水开,而是等水开了,水壶会自动的通知他。-异步阻塞
老王想了想,不会呀,既然水壶可以通知我,那我为什么还要傻傻的站在那里等呢,嗯,得换个方法。
- 老王还是使用响水壶煮水,跑到客厅上网去,等着响水壶自己把水煮熟了以后通知他。-异步非阻塞
老王豁然,这下感觉轻松了很多。
JAVA IO模型
BIO
JDK1.4以前都是使用的bio
- 阻塞在读写方法
- 用阻塞到线程来改进性能,但是线程也是一个大的开销
- 阻塞点
- server.accept()
- inputstream.read()
- 缺点
- 单线程情况下只能有一个客户端访问
- 用线程池可以有多个客户端连接,但是非常消耗性能
NIO
New IO,Single thread blocked on selection
阻塞点
- selector.select();//当注册的事件到达时 该方法返回 ,否则一直阻塞
- select()也可以不阻塞 ,select(millisecond) wakeup() selectNow()
- 单线程可以服务多个客户端
Select模式
- 学习了linux的多路复用技术
- "多路复用" --这里“多路”指的是多个网络连接,“复用”指的是复用同一个线程。采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络 IO 的时间消耗)
- 如果你看select()方法的实现 你会发现:它是用c写的
- windows通过winsocket实现
- linux通过select/poll/epoll实现
- 同步非阻塞 nio v1
- 实现IO事件的轮询方式
- 常用的网络通信框架 mina,netty
原理
selector要管理的事情:(所有的io事件)
- 客户端的连接
- 服务端的accept
- 客户端和服务端的读写
选择器:当io事件注册给我们的selector时,selector会分配一个key标记它,当io事件完成时通过这个标记来找到相应的管道,然后通过管道来发送和接收数据等操作
数据缓冲区:bytebuffer 提供很多读写方法
重要API:
// Selector
Selector select = Selector.open();
// Server point
ServerSocketChannel
// client point
SocketChannel
// 获取io事件keys
Selectionkey keys = Selector.selectedKeys();
// 注册到selector
channel.register(Selector,SelectedKeys.OP_WRITE)
例子
-
客人到餐厅点菜
-
餐厅(系统) ; 餐厅大门(ServerSocketChannel); 客人(客户端-SocketChannel); 服务员(selector + 线程);
AIO
-
jdk1.7以后 nio v2
-
学习了linux epoll 模式
-
原理
-
AsynchronousServerSocketChannel
-
AsynchronousSocketChannel
-
用户处理器:interface CompletionHandler
- 这个接口向操作系统发起IO请求,当完成后处理具体逻辑,否则做自己该做的事情
- completed(V result, A attachment)方法
- fail(Throwable exc result, A attachment)方法
-
小结
- NIO AIO 原理就是在原来的(serversocket,socket)基础上做了改进
- 对读写管道进行了抽象,管道Channel
- 一个连接(TCP,UDP) 可以对应有多个管道
Netty
运用在那些领域?
- 分布式进程通信
例如: hadoop、dubbo、akka , rocketmq等具有分布式功能的框架,底层RPC通信都是基于netty实现的 - 游戏服务器开发