IO
IO就是把从网络请求中获取到的数据存到socket的缓冲区中,然后应用程序取数据处理。IO进行分类:
-
按功能来分:输入流(input)、输出流(output)。
-
按类型来分:字节流 和 字符流。
字节流和字符流有什么区别?
- 字节流按 8 位传输,以字节为单位输入输出数据。常用的抽象类:InputStream、OutputStream
- 字符流按 16 位传输,以字符为单位输入输出数据。常用的抽象类:Reader、Writer
但是不管文件读写还是网络发送接收,信息的最小存储单元都是字节。
而I/O 模型就是指使用什么样的通道传输数据,这很大程度上决定了程序通信的性能。BIO、NIO、AIO三类模型之间的区别就在于取数据的动作是同步还是异步,阻塞还是非阻塞。先介绍这四个概念的区别。
阻塞与非阻塞
阻塞与非阻塞指的是单个线程内遇到同步等待时,是否在原地不做任何操作。
- 阻塞指的是遇到同步等待后,一直在原地等待同步方法处理完成。
- 非阻塞指的是遇到同步等待,不在原地等待,先去做其他的操作,隔断时间再来观察同步方法是否完成。
阻塞与非阻塞关注的是线程是否在原地等待。
同步与异步
-
同步:一定要等任务执行完了,得到结果,才能执行下一个任务。
-
异步:不需要等待上一个任务执行完成,就可以继续运行下面的任务。当有结果返回时系统会通知进程进行处理,这样可以提高执行的效率。
原理是把前面的任务交由其他线程执行,把主线程解放出来,不会阻塞主线程。
异步是天然非阻塞的,而这个非阻塞是对主线程而言。
问题1:什么样的任务适合用异步?
如果几个任务互相独立,其中一个执行时间较长,那么一般就用异步地方式做这件事。
问题2:异步是并行吗?
异步意味着不等待任务结束,并没有强制要求两个任务「同时」进行。JS 引擎不能同时做两件事,以 setTimeout 为例,setTimeout 里面的代码一定会在当前环境中的任务执行完了「之后」才执行。
但是 AJAX 请求是可以与 JS 代码同时进行的,因为这个请求不是由 JS 引擎负责,而是由浏览器网络模块负责。
BIO、NIO、AIO
BIO(Blocking IO),就是同步阻塞IO,也就是传统的IO。同步规定了他必须等待缓冲区内的数据就绪才进入下一步操作,阻塞规定他必须原地等待,不能去干别的事。针对网络通信都是一个线程处理一个请求。
NIO(Non-Blocking IO),就是同步非阻塞IO。他和BIO的区别就是不必原地等待,可以先做一些其他操作,只是需要定时轮询检查IO缓冲区数据是否就绪。Java中的NIO 还加上了 IO多路复用技术,轮询时可以查看多个缓冲区。轮询任务交给系统级别的select或epoll模型,由系统进行监控,减轻用户线程负担。
AIO是真正意义上的异步非阻塞IO模型。 NIO中,轮询还是阻塞的,并非真正解放当前线程。而真正的理想的异步非阻塞IO应该让内核系统完成,用户线程只需要告诉内核,当缓冲区就绪后,通知我或者执行我交给你的回调函数。
例子讲解
商场里有一家店很好吃,但经常要排队。
- A顾客来到后,排队等了一小时,然后才开始吃饭。(BIO)
- B顾客来到后,他一看要等挺久,于是去逛商场,每次逛一会就跑回来看有没有排到他。于是他最后既购了物,又吃上了饭。(NIO)
- C顾客是会员,他来到后店长让他先去商场随便逛,等下有位置立马打电话给他。于是C顾客不用干坐着等,也不用每过一会儿就跑回来看有没有等到,最后也顺利吃上了饭(AIO)