博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
BIO、NIO,AIO的区别
阅读量:3968 次
发布时间:2019-05-24

本文共 5153 字,大约阅读时间需要 17 分钟。

BIO:阻塞IO

概念图示

同步并阻塞IO(传统阻塞型)服务器实现为一个连接一个线程,即客户端有请求服务端就需要启动一个线程,但是这个连接如果不做任何处理,就会浪费资源,如图所示:

在这里插入图片描述

代码实现

服务端:

package BIO;import java.net.InetSocketAddress;import java.net.ServerSocket;import java.net.Socket;public class Server {
public static void main(String[] args) throws Exception{
ServerSocket socket = new ServerSocket(); socket.bind(new InetSocketAddress("127.0.0.1",8888)); while (true){
//这里accept的时候会发送阻塞 Socket s = socket.accept(); new Thread(() ->{
handle(s); }).start(); } } static void handle(Socket socket){
try {
byte[] bytes = new byte[1024]; //这里read的时候会阻塞 int len = socket.getInputStream().read(bytes); System.out.println(new String(bytes,0,len)); //这里write的时候会阻塞 socket.getOutputStream().write(bytes,0,len); socket.getOutputStream().flush(); }catch (Exception e){
e.printStackTrace(); } }}

客户端:

package BIO;import java.net.Socket;import java.nio.charset.StandardCharsets;public class Client {
public static void main(String[] args) throws Exception{
Socket socket = new Socket("127.0.0.1",8888); socket.getOutputStream().write("Hello!".getBytes(StandardCharsets.UTF_8)); socket.getOutputStream().flush(); System.out.println("write over"); byte[] bytes = new byte[1024]; int len = socket.getInputStream().read(bytes); System.out.println(new String(bytes,0,len)); socket.close(); }}

适用场景

适用于连接数目较小且固定的框架,对服务器资源要求高,并发局限于应用中,jdk1.4以前的唯一选择,程序简单。

从代码中我们可以知道,阻塞IO有很多的地方都会发送阻塞。

  • 在服务端在执行accept()的时候,如果没有客户端连接,那么就会进入阻塞状态;
  • 在服务端的执行代码中,getInputStream的read()和getOutputStream的write()方法执行的时候,也会发生阻塞。

NIO:同步非阻塞IO

概念图示

同步非阻塞IO,服务器实现模型为一个线程处理多个请求,即客户端发送的请求都会注册到多路复用器(selector)上,就相当于一个大管家,让后进行轮询,多重复用器轮询到有IO请求就处理但是不再另启动线程。

并且,selector轮询的时候,不仅会查看有没有客户端需要连接,而且会查看已经连接的通道,看看是否由数据需要传输等等,名副其实的管家。

如图所示:

1、单线程(Single Thread)模型:

在这里插入图片描述

2、多线程(Reactor模式):

在这里插入图片描述

类似于我们java中的线程池,谁空闲谁去处理,就像Selector管家领着一帮工人,连接和读写交给不同线程去做。

代码实现

服务端

package NIO;import java.io.IOException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.ServerSocketChannel;import java.nio.channels.SocketChannel;import java.nio.charset.StandardCharsets;import java.util.Iterator;import java.util.Set;public class Server {
public static void main(String[] args) throws Exception{
//可以同时读也可以同时写 ServerSocketChannel ssc = ServerSocketChannel.open(); ssc.socket().bind(new InetSocketAddress("127.0.0.1",8888)); //设定阻塞为false,即非阻塞模型 ssc.configureBlocking(false); System.out.println("Selector start"); Selector selector = Selector.open(); //轮询有没有客户端需要连接,对客户端连接最感兴趣 ssc.register(selector, SelectionKey.OP_ACCEPT); while (true){
//阻塞方法,有一件事发生了才会处理 selector.select(); Set
keys = selector.selectedKeys(); Iterator
iterator = keys.iterator(); while (iterator.hasNext()){
SelectionKey key = iterator.next(); iterator.remove(); handle(key); } } } static void handle(SelectionKey key){
if (key.isAcceptable()){
try {
ServerSocketChannel ssc = (ServerSocketChannel) key.channel(); SocketChannel sc = ssc.accept(); sc.configureBlocking(false); sc.register(key.selector(),SelectionKey.OP_READ); }catch (IOException e){
e.printStackTrace(); }finally {
} }else if (key.isReadable()){
SocketChannel sc = null; try {
sc = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.allocate(512); buffer.clear(); int len = sc.read(buffer); if (len != -1){
System.out.println(new String(buffer.array(),0,len)); } ByteBuffer writeBuffer = ByteBuffer.wrap("Hello!".getBytes(StandardCharsets.UTF_8)); sc.write(writeBuffer); }catch (IOException e){
e.printStackTrace(); }finally {
if (sc != null){
try {
sc.close(); }catch (IOException e){
e.printStackTrace(); } } } } }}

适用场景

适用于连接数目多且连接较短(轻操作)的架构,比如:聊天服务器,弹幕系统,服务器之间通信等。jdk1.4之后开始,编程较为复杂。

AIO:异步非阻塞IO

又称为NIO的2.0版本,异步非阻塞IO,服务器实现模式为一个有效请求一个线程,客户端的IO请求都是由OS先完成了再通知启动线程进行处理。

也就是说,NIO中,我们必须对客户端的请求进行轮询,方才可以进行我们的读写操作,实际上这样依旧浪费资源,能不能有中模式,让读写或者其他请求需要处理的时候,通知线程呢?

AIO就实现了这个功能。不再需要轮询,异步IO。

概念图示

在这里插入图片描述

再AIO的模型中,每当客户端请求连接的时候,操作系统就会通知一个类似于我们NIO中Selector管家的角色,让他进行也只是进行连接,至于后续的读写等操作,则依旧需要线程池中的”工人线程“去解决。

适用场景

适用于连接数量多且连接时间长(重操作)的架构,比如相册服务器,充分调用os并发操作,编程复杂,jdk1.7之后支持。

Netty

Netty是对NIO进行了封装,并且封装成了AIO的模样,因为有时候AIO的效率不一定高于NIO。

转载地址:http://otjki.baihongyu.com/

你可能感兴趣的文章
在存储过程之间传递数据
查看>>
迁移存储过程
查看>>
GET DIAGNOSTIC 语句
查看>>
Python 简介
查看>>
Python 注释
查看>>
Python 变量
查看>>
Python 数据类型 -- 数字
查看>>
Spring 管理对象
查看>>
Spring 自定义对象初始化及销毁
查看>>
Spring Batch 环境设置
查看>>
字符组转译序列
查看>>
字符转译序列
查看>>
Java 数据类型
查看>>
UTF-16 编码简介
查看>>
Java 变量名
查看>>
Java 四舍五入运算
查看>>
Spring Batch 例子: 运行系统命令
查看>>
Spring Batch 核心概念
查看>>
Spring Batch 例子: 导入定长文件到数据库
查看>>
正则表达式
查看>>