理解tomcat中的BIO、NIO、AIO、ARP
理解tomcat中的BIO、NIO、AIO、ARP
tomcat作为springboot中默认的web容器,了解tomcat的运转可以帮助我们更好的去调整tomcat的参数达到更好的性能
前置知识
- I/O就是Input/Output,收别人的数据到本机叫Input,本级发数据出去叫Output
- 网络I/O请求会先到网卡然后到内核态再到用户态
- CPU比内存快、内存比硬盘、网卡等外设快
- 所有I/O操作需要被加载到用户态内存,用户态程序才能直接操作
- 想要效果高,必须让所有的资源都不闲置
- tomcat不处理请求,会接受请求,转发到具体的容器中
- 一个socket连接代表一个客户端,一个socket可以发送多份请求不断开
scoket测试工具
启动程序是jar包,必须要有jre环境
链接:https://sockettest.sourceforge.net

tomcat中的 I/O 模型
BIO 同步阻塞IO
每一个socket连接后,tomcat都会有一个线程去全程去陪伴,把请求转发到具体的容器中后,这个线程还在阻塞,等待容器返回数据,只有socket连接断开了,才会回收这个线程。tomcat7或以下默认,比较简单、稳定,适合连接数比较少的
模拟代码如下:
public class BioServer {
static ExecutorService executorService = Executors.newCachedThreadPool();
public static void main(String[] args) {
try {
// 启动服务,绑定8080端口
ServerSocket serverSocket = new ServerSocket();
serverSocket.bind(new InetSocketAddress(8080));
System.out.println("开启服务");
while (true){
System.out.println("等待客户端建立连接");
// 监听8080端口,获取客户端连接
Socket socket = serverSocket.accept(); //阻塞
System.out.println("建立连接:"+socket);
executorService.submit(()->{
//业务处理
try {
handler(socket);
} catch (IOException e) {
e.printStackTrace();
}
});
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//TODO 资源回收
}
}
private static void handler(Socket socket) throws IOException {
byte[] bytes = new byte[1024];
System.out.println("等待读取数据");
int read = socket.getInputStream().read(bytes); // 阻塞
if(read !=-1) {
System.out.println("读取客户端发送的数据:" +
new String(bytes, 0, read));
}
}
}
NIO 同步非阻塞
一个socket连接过来,会经历以下步骤
- LimitLatch:连接控制器,负责维护连接数计算,连接数默认是 8192,达到这个阀值后,就会拒绝连接请求。如果要调整修改配置文件server.tomcat.max-connections属性
- Acceptor:Acceptor 跑在一个单独的线程里,它在一个死循环里调用 accept 方法来接收新连接,一旦有新的连接请求到来,accept 方法返回一个 Channel 对象,接着把 Channel 对象交给 Poller 去处理
- Poller:Poller 的本质是一个 Selector,也跑在单独线程里。Poller 在内部维护一个 Channel 数组,它在一个死循环里不断检测 Channel 的数据就绪状态,一旦有 Channel 可读,就生成一个 SocketProcessor 任务对象扔给Executor 去处理
- Executor: Executor 就是线程池,负责运行 SocketProcessor 任务类,SocketProcessor 的 run 方法会调用Http11Processor 来读取和解析请求数据。Http11Processor 是应用层协议的封装,它会调用容器获得响应,再把响应通过 Channel 写出

tomcat8及以上默认, springboot2.3.12.RELEASE内嵌tomcat是9.0.46版本默认也是这个
模拟代码:
public class NioServer {
public static void main(String[] args) {
List<SocketChannel> list = new ArrayList<>(); // 缓存所有的socket
ByteBuffer byteBuffer = ByteBuffer.allocate(1024); // 缓存区的大小
try {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
// 监听8080
serverSocketChannel.bind(new InetSocketAddress(8080));
// channel非阻塞
serverSocketChannel.configureBlocking(false);
System.out.println("NioServer 启动....");
while (true){
// 非阻塞
SocketChannel socketChannel = serverSocketChannel.accept();
Thread.sleep(1000);
if(socketChannel == null){
System.out.println("没有新的客户端建立连接");
}else {
System.out.println("新的客户端建立连接");
// channel非阻塞
socketChannel.configureBlocking(false);
// 将新的socket添加到 list
list.add(socketChannel);
}
//遍历所有的socket
for(SocketChannel channel:list){
//非阻塞
int read = channel.read(byteBuffer);
if(read >0) {
//读模式
byteBuffer.flip();
System.out.println("读取客户端发送的数据:" +new String(byteBuffer.array(),0,read));
byteBuffer.clear();
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
AIO异步非阻塞
NIO 和 AIO(NIO2) 最大的区别是,一个是同步一个是异步。异步最大的特点是,应用程序不需要自己去触发数据从内核空间到用户空间的拷贝。

没有 Poller 组件,也就是没有 Selector。在异步 I/O 模式下,Selector 的工作交给
内核来做了。
Linux 内核没有很完善地支持异步 I/O 模型,因此 JVM 并没有采用原生的 Linux 异步 I/O,而是在应用层面通过 epoll 模拟了异步 I/O 模型。因此在 Linux 平台上,Java NIO 和 Java NIO2 底层都是通过 epoll 来实现的,但是 Java NIO 更加简单高效。如果你的 Tomcat 跑在 Linux 平台上,建议不使用NIO2
模拟代码:
public class AioServer {
public AsynchronousServerSocketChannel serverSocketChannel;
public static void main(String[] args) throws Exception {
new AioServer().listen();
Thread.sleep(Integer.MAX_VALUE);
}
private void listen() throws IOException {
//1. 创建一个线程池
ExecutorService es = Executors.newCachedThreadPool();
//2. 创建异步通道群组
AsynchronousChannelGroup acg = AsynchronousChannelGroup.withCachedThreadPool(es, 1);
//3. 创建服务端异步通道
serverSocketChannel = AsynchronousServerSocketChannel.open(acg);
//4. 绑定监听端口
serverSocketChannel.bind(new InetSocketAddress(8080));
System.out.println("AioServer 启动....");
//5. 监听连接,传入回调类处理连接请求
serverSocketChannel.accept(this, new CompletionHandler<AsynchronousSocketChannel, AioServer>() {
//
// //具体处理连接请求的就是completed方法,它有两个参数:第一个是异步通道,第二个就是上面传入的AioServer对象
@Override
public void completed(AsynchronousSocketChannel socketChannel, AioServer attachment) {
try {
if (socketChannel.isOpen()) {
System.out.println("接收到新的客户端的连接,地址:"
+ socketChannel.getRemoteAddress());
final ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
//调用 read 函数读取客户端发送的数据
socketChannel.read(byteBuffer, socketChannel,
new CompletionHandler<Integer, AsynchronousSocketChannel>() {
@Override
public void completed(Integer result, AsynchronousSocketChannel attachment) {
try {
//读取请求,处理客户端发送的数据
byteBuffer.flip();
String content = Charset.defaultCharset()
.newDecoder().decode(byteBuffer).toString();
System.out.println("服务端接受到客户端发来的数据:" + content);
} catch (CharacterCodingException e) {
e.printStackTrace();
}
}
@Override
public void failed(Throwable exc, AsynchronousSocketChannel attachment) {
exc.printStackTrace();
try {
attachment.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
} catch (IOException e) {
e.printStackTrace();
}finally {
//当有新的客户端接入的时候,直接调用accept的方法
attachment.serverSocketChannel.accept(attachment, this);
}
}
@Override
public void failed(Throwable exc, AioServer attachment) {
exc.printStackTrace();
}
});
}
}
APR异步非阻塞
APR方式全名叫Apache Portable Runtime,需要额外去下载安装配置,NIO2是调用java库去实现异步的,而ARP是直接通过JNI (Java Native Interface)去操作系统是实现异步,APR 能够使用高级 IO 功能 (如sendfile, epoll, OpenSSL),sendfile主要是对静态文件提升很大,换APR也主要是这个原因其他的提升也不是特别大
附上对比图

springboot配置apr教程:https://www.jianshu.com/p/f716726ba340
理解tomcat中的BIO、NIO、AIO、ARP的更多相关文章
- JAVA中的BIO,NIO,AIO
在了解BIO,NIO,AIO之前先了解一下IO的几个概念: 1.同步 用户进程触发IO操作并等待或者轮询的去查看IO操作是否就绪, 例如自己亲自出马持银行卡到银行取钱 2.异步 用户触发IO操作以后, ...
- Apache Tomcat 7 Configuration BIO NIO AIO APR ThreadPool
Apache Tomcat 7 Configuration Reference (7.0.93) - The Executor (thread pool)https://tomcat.apache.o ...
- Netty5序章之BIO NIO AIO演变
Netty5序章之BIO NIO AIO演变 Netty是一个提供异步事件驱动的网络应用框架,用以快速开发高性能.高可靠的网络服务器和客户端程序.Netty简化了网络程序的开发,是很多框架和公司都在使 ...
- Netty序章之BIO NIO AIO演变
Netty序章之BIO NIO AIO演变 Netty是一个提供异步事件驱动的网络应用框架,用以快速开发高性能.高可靠的网络服务器和客户端程序.Netty简化了网络程序的开发,是很多框架和公司都在使用 ...
- (转)也谈BIO | NIO | AIO (Java版)
原文地址: https://my.oschina.net/bluesky0leon/blog/132361 关于BIO | NIO | AIO的讨论一直存在,有时候也很容易让人混淆,就我的理解,给出一 ...
- 拿搬东西来解释udp tcpip bio nio aio aio异步
[群主]雷欧纳德简单理解 tcpip是有通信确认的面对面通信 有打招呼的过程 有建立通道的过程 有保持通道的确认 有具体传输udp是看到对面的人好像在对面等你 就往对面扔东西[群主]雷欧 ...
- 也谈BIO | NIO | AIO (Java版--转)
关于BIO | NIO | AIO的讨论一直存在,有时候也很容易让人混淆,就我的理解,给出一个解释: BIO | NIO | AIO,本身的描述都是在Java语言的基础上的.而描述IO,我们需要从两个 ...
- IO回忆录之怎样过目不忘(BIO/NIO/AIO/Netty)
有热心的网友加我微信,时不时问我一些技术的或者学习技术的问题.有时候我回微信的时候都是半夜了.但是我很乐意解答他们的问题.因为这些年轻人都是很有上进心的,所以在我心里他们就是很优秀的,我愿意多和努力的 ...
- I/O模型系列之三:IO通信模型BIO NIO AIO
一.传统的BIO 网络编程的基本模型是Client/Server模型,也就是两个进程之间进行相互通信,其中服务端提供位置信息(绑定的IP地址和监听端口),客户端通过连接操作向服务端监听的地址发起连接请 ...
- 【netty】(1)---BIO NIO AIO演变
BIO NIO AIO演变 Netty是一个提供异步事件驱动的网络应用框架,用以快速开发高性能.高可靠的网络服务器和客户端程序.Netty简化了网络程序的开发,是很多框架和公司都在使用的技术. Net ...
随机推荐
- 异常try-catch-finally与存储和JSON.parse
捕获异常 捕获异常:处理可能出现的异常,当发生错误后,我们对它进行处理,不让程序崩溃. 异常处理 try-catch-finally try{ // 可能出现异常的:代码1 }catch(err){ ...
- Q:plsql中文显示??处理
1.查询数据库字符集select userenv('language') from dual; 2.修改NLS_LANG环境变量:将NLS_LANG环境变量设置为正确的字符集 windows设置系统环 ...
- 清华大学推出的 DeepSeek 从入门到精通(104页)免费教程!
前言 最近 DeepSeek 的出现让 AI 在国内掀起了一股浪潮,各大媒体.平台都在讨论和推广 DeepSeek,帮助各行各样使用 AI 不再有困难.今天大姚给大家分享一个由清华大学推出的.免费的: ...
- 安川机器人HW1171766-A本体线缆维修详解
随着工业自动化程度的不断提高,安川机器人在生产线上的应用越来越广泛.然而,在长期运行过程中,安川机器人本体线缆可能会出现磨损.老化.断裂问题,这些问题不仅会影响机器人的正常运行,还可能导致生产线的停滞 ...
- 2分钟学会 DeepSeek API,竟然比官方更好用!
大家好,我是程序员鱼皮.最近 DeepSeek AI 太火了,效果也很强,但致命问题是 不稳定, 经常给我返回 服务器繁忙,请稍后再试,甚至让我怀疑自己被杀熟了. 也有网友说,第一次使用成功率很高,第 ...
- 反范式设计,冗余用户姓名,修改用户姓名后,业务表同步更新 -- MySQL 存储过程
反范式设计,冗余用户姓名,通过存储过程进行业务表的同步更新. 所有的表,在创建的时候,都加了创建人.修改人的字段..用户姓名发生变化时,要将所有的表都更新一遍. 创建存储过程 MySQL CREATE ...
- 最新版go-cqhttp的sign 签名服务器搭建教程
安装go-cqhttp 传送门 自建sign签名服务器容器: 拉取镜像(只支持amd64) docker pull hansaes/unidbg-fetch-qsign:latest 启动容器 doc ...
- 基于自注意力机制的轻量级人体姿态估计(Lightweight Human Pose Estimation Based on Self-Attention Mechanism)
写在前面 本文是一篇于2023年3月21日发表在2023 International Conference on Big Data, Environmental Industry and Materi ...
- 2024数证杯决赛团体赛wp
2024数证杯决赛团体赛wp 容器密码:mW7@B!tRp*Xz46Y9#KFUV^J2&NqoHqTpLCE%8rvGW(AX#1k@YL3$M5!bWY*9HLFq7UZR6^T!XoVm ...
- python xlrd 读取表格 单元格值被覆盖
代码实现顺序: 按行读取 按列读取 满足if条件 单元格值赋值给字典 实现代码: datas = []# 定义一个空列表 for i in range (3,nrows): sheet_data={} ...