BIO:

简介:同步阻塞,实现的模式为一个连接一个线程,每当有一个客户端连接,需要为其单独分配一个线程,如果连接不作任何操作会造成不必要的线程开销,并且无法支持大并发,一般springboot默认tomcat的默认的最大工作线程数量就是200,那就只支持200的并发。

alt

BIO编程流程

  1. 服务器端启动一个SeverSocket
  2. 客户端启动Socket对服务器端发起通信,默认情况下服务器端需为每个客户端创建一个线程与之通讯
  3. 客户端发起请求后,先咨询服务器端是否有线程响应,如果没有则会等待或被拒绝
  4. 如果有线程响应,客户端线程会等待请求结束后,再继续执行

BIO的问题

  1. 服务器端在监听客户端连接时(serverSocket.accept()),服务器端处于阻塞状态,不能处理其他事务
  2. 服务器端需要为每个客户端建立一个线程,虽然可以用线程池来优化,但在并发较大时,线程开销依旧很大
  3. 当连接的客户端没有发送数据时,服务器端会阻塞在read操作上,等待客户端输入,造成线程资源浪费

NIO:

简介:从JDK1.4开始,java提供了一系列改进输入/输出的新特性,统称为NIO,全称n为new I/O,是同步非阻塞的,所以也有人称为non-blocking I/O。NIO的相关类都放在java.nio包或其子包下,并对原先java.io包中许多类进行了改写。alt

NIO的三大核心

  • 缓冲区(Buffer)

NIO是面向缓冲区, 或者说是面向块编程的。在NIO的IO传输中,数据会先读入到缓冲区,当需要时再从缓冲区写出,这样减少了直接读写磁盘的次数,提高了IO传输的效率。

缓冲区(buffer)本质上是一个可以读写数据的内存块,即在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入和输出的数据,这部分预留的存储空间就叫缓冲区。

在NIO程序中,通道channel虽然负责数据的传输,但是输入和输出的数据都必须经过缓冲区buffer。

  • 通道(Channel)

在NIO程序中服务器端和客户端之间的数据读写不是通过流,而是通过通道来读写的。

通道类似于流,都是用来读写数据的,但它们之间也是有区别的:

通道是双向的,即可以读也可以写,而流是单向的,只能读或写

通道可以实现异步读写数据

通道可以从缓冲区读数据,也可以把数据写入缓冲区

java中channel的相关类在java.nio.channel包下。Channel是一个接口,其常用的实现类有:

FileChannel:用于文件的数据读写,其真正的实现类为FileChannelImpl

DatagramChannel:用于UDP的数据读写,其真正的实现类为DatagramChannelImpl

ServerSocketChannel:用于监听TCP连接,每当有客户端连接时都会创建一个SocketChannel,功能类似ServerSocket,其真正的实现类为ServerSocketChannelImpl

SocketChannel:用于TCP的数据读写,功能类似节点流+Socket,其真正的实现类为SocketChannelImpl

  • 选择器(Selector)

在NIO程序中,可以用选择器Selector实现一个选择器处理多个通道,即一个线程处理多个连接。只要把通道注册到Selector上,就可以通过Selector来监测通道,如果通道有事件发生,便获取事件通道然后针对每个事件进行相应的处理。这样,只有在通道(连接)有真正的读/写事件发生时,才会进行读写操作,大大减少了系统开销,并且不必为每个连接创建单独线程,就不用去维护过多的线程。