Java io
IO的基本分类
data = socket.read();socket本意为套接字,为ip+端口,我理解为一个数据载体
(BIO)阻塞io:进程系统调用获取数据后,没有等到数据,则陷入阻塞状态。等到IO获取数据后,进程才就绪状态
(NIO not block io)非阻塞io:进程系统调用获取数据后,没有等到数据,则立即返回。循环往复
(NIO new io)多路复用io.:非阻塞的延伸,进程和IO进程不再是一对一而是一对多的关系,会一次性循环
同步非阻塞模型:不再创建线程去IO,而是需要是发出请求给acceptor,acceptor不断去轮询多个 socket 的状态,只有当 socket 真正有读写事件时,才真正调用实际的 IO 读写操作。因为在多路复用 IO 模型中,只需要使用一个线程就可以管理多个 socket,系统不需要建立新的进程或者线程,并且只有在真正有 socket 读写事件进行时,才会使用 IO 资源,所以它大大减少了资源占用率(select,poll,epoll)
(AIO)异步 IO 模型
在异步 IO 模型中,用户线程发起 read 操作,立刻就可以开始去做其它的事。然后,内核线程会等待数据准备完成,然后内核线程将数据拷贝到用户线程的缓冲区(磁盘等位置),当这一切都完成之后,内核会给用户线程发送一个信号,告诉它 read 操作完成
多路复用IO和AIO的区别:多路复用IO用户线程需要主动去读取数据,而AIO内核线程已经帮用户读区数据,用户直接使用
所以同步与异步的区别在于:谁去读取数据或者叫是否经历阻塞
参考资料
注意和Java调用的区别:
Java调用:同步调用,异步调用,
回调:A调用B的同时传入函数指针,B会调用A的函数指针
BIO
Javaio包:
BIO:blockIO,Java的基本IO都是阻塞IO
经典模式:
Acceptor模式:即每当一个client线程访问,服务器创建一个线程来回答。
优化:依靠线程池模式
① 服务器端的Server是一个线程,线程中执行一个死循环来阻塞的监听客户端的连接请求和通信。
② 当客户端向服务器端发送一个连接请求后,服务器端的Server会接受客户端的请求,ServerSocket.accept()从阻塞中返回,得到一个与客户端连接相对于的Socket
③ 构建一个handler,将Socket传入该handler。创建一个线程并启动该线程,在线程中执行handler,这样与客户端的所有的通信以及数据处理都在该线程中执行。当该客户端和服务器端完成通信关闭连接后,线程就会被销毁
④ 然后Server继续执行accept()操作等待新的连接请求
Java nio :new io
NIO 主要有:Channel(通道),Buffer(缓冲区), Selector。
传统 IO 基于字节流和字符流进行操作,而 NIO 基于 Channel 和 Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区 中,或者从缓冲区写入到通道中。Selector(选择区)用于监听多个通道的事件(比如:连接打开, 数据到达)。因此,单个线程可以监听多个数据通道。
Channel:“通道”。Channel 和 IO 中的 Stream(流)是差不多一个等级的。只不过 Stream 是单向的而 Channel 是双向 的,既可以用来进行读操作,又可以用来进行写操作。面向缓冲区
Buffer:缓冲区,实际上是一个容器,是一个连续数组。Channel 提供从文件、 网络读取数据的渠道,但是读取或写入的数据都必须经由
buffer
所有的缓冲区类型都继承于抽象类Buffer
1)使用NIO读取数据
在前面我们说过,任何时候读取数据,都不是直接从通道读取,而是从通道读取到缓冲区。所以使用NIO读取数据可以分为下面三个步骤:
FileInputStream fin = new FileInputStream(“c:\test.txt”);
从FileInputStream获取Channel ——FileChannel fc = fin.getChannel();
创建Buffer ——ByteBuffer buffer = ByteBuffer.allocate(1024);
文本将数据从Channel写入到Buffer中——fc.read(buffer);
用户从Buffer中直接读数据——byte b = buffer.get();
2)使用NIO写入数据
FileOutputStream fout = new FileOutputStream( “e:\test.txt” );
从FileOutputStream获取Channel——FileChannel fc = fout.getChannel();
创建Buffer—— ByteBuffer buffer = ByteBuffer.allocate( 1024 );
用户将数据直接写入Buffer——buffer.put( message[i] );
文本从Channel中读入Buffer数据—— fc.write( buffer );
综上所述,用户都是直接与Buffer接触。而文本才利用channel与Buffer接触
Selector 类是 NIO 的核心类,Selector 能够检测多个注册的通道上是否有事件发生,如果有事件发生,便获取事件然后针对每个事件进行相应的响应处理。用一个单线程就可以管理多个通道,也就是管理多个连接。
优点:
1:BIO面向流,NIO面向缓冲区
Java IO 面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。此外,它不能前后移动流中的数据。
数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这