最近在进行tomcat优化,发现tomcat connector并发支持bio nio apr,想要理解tomcat并发离不开java io的理解。所以本文先探讨java对io的支持。java的io需要操作系统的支持,本文描述linux系统对io的支持,windows系统因为java生产环境使用少不再论述。
一、linux操作系统io的支持
1.同步阻塞 I/O(bio)
在这里首先解释两个概念,kernel与application。
kernel(内核)是一段计算机程序,这个程序直接管理管理硬件,包括CPU、内存空间、硬盘接口、网络接口等等。所有的计算机操作都要通过内核传递给硬件。
application(应用)是在内核基础上的应用,比如说firefox浏览器,tomcat容器,一个计算流体模型等等
详情可参考https://blog.csdn.net/chenkaixin_1024/article/details/70158065。
言归正传,对于同步阻塞I/O而言:
第一步,应用程序发起系统调用(system call),然后应用程序阻塞挂起。
第二步,切换到内核上下文,对于网络请求通常涉及等待网络上的数据分组到达,然后被复制到内核的某个缓冲区。
第三步,把数据从内核缓冲区复制到应用进程缓冲区。
第四步,应用程序就会解除阻塞。
优点:能够及时返回数据,无延迟。
缺点:等待要付出性能的代价
2.同步非阻塞I/O(nio)
同步非阻塞时至是 “每隔一会儿瞄一眼进度条” 的轮询(polling)方式。
第一步,应用程序发起系统调用(system call)。
第二步,应用程序不会阻塞,内核马上返回给进程,如果数据还没准备好,此时会返回一个error,说明这个命令不能立即满足(EAGAIN
或 EWOULDBLOCK
)。
第三步,应用程序可以使用空闲时间处理其他请求。
第四步,过一段时间,应用程序再次发起系统调用(system call),如过数据仍然没有准备好,重复执行第二部,直到数据准备好,执行第五步。
第五步,把数据从内核缓冲区复制到应用进程缓冲区。需要注意,拷贝数据整个过程,进程仍然是属于阻塞状态。
优点:能够在等待任务完成的时间里干其他活了(包括提交其他任务,也就是 “后台” 可以有多个任务在同时执行)。
缺点:任务完成的响应延迟增大了,因为每过一段时间才去轮询一次read操作,而任务可能在两次轮询之间的任意时间完成。这会导致整体数据吞吐量的降低。
3.异步非阻塞 I/O(aio)
相对于同步IO,异步IO不是顺序执行。用户进程进行系统调用(system call)之后,无论内核数据是否准备好,都会直接返回给用户进程,然后用户态进程可以去做别的事情。等到socket数据准备好了,内核直接复制数据给进程,然后从内核向进程发送通知。IO两个阶段,进程都是非阻塞的。
Linux 的异步 IO(AIO)支持是 2.6.22 才引入的,还有很多系统调用不支持异步 IO。Linux 的异步 IO 最初是为数据库设计的,因此通过异步 IO 的读写操作不会被缓存或缓冲,这就无法利用操作系统的缓存与缓冲机制
。
详情参考https://blog.csdn.net/bpingchang/article/details/51419890
二、java 包对io的支持
BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解。
NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持。
AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。