必要的基础
IO:输入输出(IO)是指计算机同任何外部设备之间的数据传递。
同步与异步
阻塞与非阻塞
阻塞:阻塞就是发起一个请求,调用者一直等待请求结果返回,也就是当前线程会被挂起,无法从事其他任务,只有当条件就绪才能继续。
非阻塞:非阻塞就是发起一个请求,调用者不用一直等着结果返回,可以先去干其他事情。
阻塞与非阻塞指的的是当不能进行读写(网卡满时的写/网卡空的时候的读)的时候,I/O 操作立即返回还是阻塞;
同/异步 和 阻塞/非阻塞 关系
那么同步阻塞(BIO)、同步非阻塞(NIO)和异步非阻塞(AIO)又代表什么意思呢?上面的太抽象了
举个生活中简单的例子,你妈妈让你烧水,小时候你比较笨啊,在哪里傻等着水开(同步阻塞)。等你稍微再长大一点,你知道每次烧水的空隙可以去干点其他事,然后只需要时不时(轮询)来看看水开了没有(同步非阻塞)。后来,你们家用上了水开了会发出声音的壶,这样你就只需要听到响声后就知道水开了,在这期间你可以随便干自己的事情,你需要去倒水了(异步非阻塞)。
BIO模型本质上是一对一的通信,也就是从客户端发起请求开始,服务端处理请求(如果资源没有准备好,请求线程会一直占用,直至请求到资源为止,这个过程中其它请求是无法被处理的),当然服务端可以通过多线程的方式,实现同时处理多个请求线程,但是多线程的使用要注意,因为线程的创建和管理非常消耗系统资源。所以这种方式对于高并发也是扛不住的。
后来通过线程池+消息队列的方式,演化出伪异步IO,服务端维护这个线程池和消息队列,如果有新的请求,服务端将其打包为一个task对象(该TasK类实现Runnable接口),将此task放入线程池中处理,通过消息队列的方式确定处理哪一个task,这种伪异步IO采用线程池实现,避免创建多个线程导致资源耗尽的问题,但是由于底层还是BIO模型,所以还没有从根本解决问题。
NIO在JDK1.4引入,位于JDK的java.nio
包中,NIO主要涉及三个概念:Buffer缓冲区、Selector选择器、Channel通道;
NIO的特点如下
一个线程可以处理多个请求
NIO提供非阻塞通信方式,BIO是阻塞的
NIO是面向缓冲区的,BIO是面向流的
避免同步IO通讯效率过低
减小线程多的压力
从图中我们可以发现,客户端和服务端可以同时使用NIO模型。
NIO固然好,但是NIO的编程难度较大,维护成本较高。所以我们可以使用NIO的框架来降低开发难度,流行基于Java NIO通信框架有Mina、Netty、Grizzly等
AIO也是基于NIO的,不过AIO是异步非阻塞的。异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。
参考文章
BIO,NIO,AIO 总结
socket通信中的IO模型
Java核心技术(进阶)-NIO基础
nio的实现原理