在Java的软件设计开发中,通信架构是不可避免的,我们在进行不同系统或者不同进程之间的数据交互,或者在高并发下的通信场景下都需要用到网络通信相关的技术
对于一些经验丰富的程序员来说,Java早期的网络通信架构存在一些缺陷,其中最令人恼火的是基于性能低下的同步阻塞式的I/O通信(BIO)
随着互联网开发下通信性能的高要求,Java在2002年开始支持了非阻塞式的I/O通信技术(NIO),它基于底层缓冲区方式读写的
无论是手游服务端,还是大型的网络游戏,Java 语言都得到越来越广泛的应用
I/O 模型:就是用什么样的通道或者说是通信模式和架构进行数据的传输和接收,很大程度上决定了程序通信的性能
Java 共支持 3 种网络编程的/IO 模型:BIO、NIO、AIO,实际通信需求下,要根据不同的业务场景和性能需求决定选择不同的I/O模型
服务器实现模式为一个连接一个线程,也就是说即客户端有连接请求时服务器端就需要启动一个线程进行处理
这样就导致如果客户端越多的话,就要启动越多的线程,也就带来一个问题,客户端过的时候服务端要提供等量的线程处理,
每个客户端在发送数据的时候都是同步的,何为同步?即服务端的线程在等待客户端数据的时候,若客户端没有发送数据或者没有数据,服务端的依然会在等待,且不能做任何事情
同步通信机制:男孩向女孩表白,女孩陷入沉思,在考虑要不要接受男孩的表白,男孩同时也在默默的等待,直到女孩做出回应
从这里我们就可以看出BIO下的情况下需要创建非常多的线程,造成不必要的线程开销,同时对线程的切换都需要很大程度开销,以及对于客户端是否有数据都要进行等待,这就是我们的同步阻塞模式的通信模式
阻塞描述:男孩子向女孩子表白之后,不管女孩子什么反应,男孩子什么事情都干不了了,茶饭不思,就一心一意的想着女孩子会不会接受呀,这种情况就非常类似于我们说的为阻塞式调用。指发出请求的一方在等待调用的结果,在收到结果之前什么都干不了,专心的等待调用结果
服务器实现模式为一个线程处理一个或者多个请求(连接),即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮会接受所有客户端的通道请求
我们只需要一个线程去管理这个多路复用器上,多路复用器会去轮询管道/通道,是否有连接、 I/O 请求,有则分配新的线程就进行处理这个管道的通信
如果说这个管道没有通信,它可以去做其他事情,就是说它依然需要轮询访问通道,但是一个通道没有数据的时候,是不需要一直等待的
相当于:男孩子表白之后,不管女孩子说先让我回去想几天,这时候男孩子还是很活跃,他并没有每天24小时想着这件事情。
他一会去打打游戏,一会去打打球。即在收到结果之前完全没有收到任何影响,这就类似于我们说的非阻塞式调用
服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理,一般适用于连接数较多且连接时间较长的应用
也就是说我们客户端的数据,它都是通过我们的操作系统来处理,操作系统处理完后再通知相对应的服务器应用去启动线程处理
异步通信机制:男孩向女孩表白,女孩立马有可能说那你给我几天时间考虑,等我考虑考好了过几天我给你发个消息告诉你结果,男孩此时并不知道最终的结果
拿山治烧水举例来说,(山治的行为好比用户程序,烧水好比内核提供的系统调用),这两组概念翻译成大白话可以这么理解:
同步阻塞:点火后傻等,不等到水开坚决不干任何事(阻塞),水开了关火(同步)
同步非阻塞:点火后去看电视(非阻塞),时不时看水开了没有,水开后关火(同步)
异步阻塞:按下开关后,傻等水开(阻塞),水开后自动断电(异步)
异步非阻塞:按下开关后,该干嘛干嘛 (非阻塞),水开后自动断电(异步)。
BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序简单易理解
NIO 方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,弹幕系统,服务器间通讯等。编程比较复杂,JDK1.4 开始支持。
AIO 方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用 OS 参与并发操作,编程比较复杂,JDK7 开始支持