Netty中真的没有使用锁吗?

news/2024/5/17 16:53:14 标签: Netty, synchronized

Netty号称是一个事件驱动&异步串行无锁化的网络通信框架.
在这里插入图片描述Netty的官方网站(https://netty.io/)中声称, 它是一个异步的, 事件驱动的网络框架.

关于事件驱动, 在之前的文章中也简单提到过, Netty内部会一直轮询ACCEPT,READ,WRITE,CONNECT等事件, 根据轮询到的不同的事件, 调用不同的方法, 做出不同的响应. 正如我们平时说的, 操作系统是基于中断驱动的, 而Netty是基于事件驱动的.

关于异步这块, 我给它的准确定义是异步串行无锁化. 然而在Netty内部会包含两类线程, 一类是执行IO操作的IO线程, 比如执行上面说的各种事件的线程就是IO线程. 还有一类线程是非IO线程(这不是废话嘛), 也就是业务线程. 虽然我说它是异步串行无锁化, 但不准确, 因为我没说主语. 到底是IO线程在异步串行无锁化, 还是非IO线程在异步串行无锁化呢? 这里说的是非IO线程, 非IO线程在执行写操作的时候, 会把写操作封装成一个写任务, 然后提交到与IO线程唯一绑定的任务队列里, 由IO线程从队列里面取出任务去执行. 而非IO线程提交完任务之后就返回了, 可以继续向下执行. 而且即便多个非IO线程同时向任务队列中提交任务, 也不会发生阻塞, 也不会加锁, 因为它是通过CAS方式操作队列的. 这个高性能的队列, 自然和JDK自带的无缘, 它是jctools里的一个队列(org.jctools.queues.MpscUnboundedArrayQueue), 专为并发而生的队列. 任务被提交到任务队列之后, IO线程就会从队列中取出任务, 逐个串行执行.

在这里插入图片描述
IO线程一直无限循环地沉浸在轮询IO事件-处理IO事件-执行队列中的任务这三件事情无法自拔.在这个过程中, IO线程也没有使用加锁的逻辑.

那么在Netty中到底哪里会使用加锁的逻辑呢? 是在申请内存的时候.

举例来说, 当网卡接收到数据之后, 通过中断通知CPU, CPU响应硬中断, 同时发起软中断请求. 操作系统的ksoftirqd线程执行软中断, 将网络数据通过协议栈处理, 最终放到socket的接收缓冲区, 唤醒IO线程(IO线程可能执行了epoll处于阻塞状态). IO线程就会读取数据, 然而数据肯定需要内存空间来保存. 这个时候IO线程就会申请堆外空间进行存储这些数据. 在申请堆外空间的时候可能就会发生加锁的情况. 关于内存申请和释放这块, 在接下来的文章中就会介绍到. 这里简单描述下IO线程申请内存空间的流程.

在这里插入图片描述
如上图所示, 当IO线程申请内存的时候, 首先会从自身的PoolThreadCache中查找是否有可用的空闲内存, 这个时候是不需要加锁的, 因为每个IO线程都有一个属于自己的PoolThreadCache. 当PoolThreadCache无可用的内存时, 这个时候就会从PoolSubpage中查找空闲内存, 这个时候就要加锁了, 因为Arena是线程共享的, PoolSubpage也是线程共享的, 这个时候加锁使用synchronized(poolSubpage) {…} , 目前的加锁力度并不是很大, 只有两个IO线程申请相同大小的内存空间, 就会向相同的PoolSubpage申请空间, 这个时候这两个IO线程才会使用同一把锁, 如果两个IO线程都需要向PoolSubpage申请空间, 但是是在不同的PoolSubpage中申请空间, 那么它们使用的是不同的锁. 假如PoolSubpage也没有适合的空闲空间, 那么就需要向Chunk申请了, 这个时候, 如果两个IO线程共享的是同一个Arean, 那么如果它们都需要向Chunk申请空间, 那么它们使用相同的锁, 即synchronized(this) {…}, 这里的this就是Arena.

此篇文章只是简单说了下, 在Netty中在申请内存空间的时候可能会存在加锁的情况, 以及申请内存的大概流程, 更详细的内存申请会在接下来的文章中说到, 而且内存申请是比较难理解的一块内容, 希望通过我的解释, 到时候能让你有所收获. 为今天的你, 加个油!


个人站点
语雀

公众号

在这里插入图片描述


http://www.niftyadmin.cn/n/527420.html

相关文章

Netty之线程唤醒wakeup

首先回顾下, Netty中的IO线程主要完成三件事 1.轮询IO事件 2.处理IO事件 3.执行任务 在轮询IO事件的过程中,在Linux系统下, 使用epoll实现. 涉及的Netty代码如下 private void select() {// ...int selectedKeys selector.select(timeoutMillis);// ...}具体源码位置: io.ne…

maven命令行下载依赖包java命令执行class

【场景和需求】 在Linux系统下, 没有第三方的集成开发工具(如IDEA), 如何下载Jar包, 以及如何运行.java文件 【解决步骤】 配置maven环境 配置Java环境 如何配置此处就不介绍了, 属于基础操作 此处以下载netty为例 在官网 https://mvnrepository.com/ 查找需要下载的依赖包…

编译OpenJDKCLion导入修改JDK源码

【下载源码】 根据OpenJDK源码下载介绍, 下载源码. 本文选择JDK8的某个tag版本( jdk-jdk8-b116 ) 【环境】 操作系统 ubuntu-20.04 64bit ant, maven, jdk 配置如下 安装依赖包 包含但不限于 sudo apt-get install libx11-dev libxext-dev libxrender-dev libxtst-dev l…

线上消息堆积与感想

【环境介绍】 1.应用服务器部署在阿里云 2.消息中间件使用阿里云RocketMQ 前两天线上发生了MQ消息堆积的情况,在我的知识认知里,消息堆积的原因是消费者消费能力差,无法及时消费消息,才会导致消息堆积. 那么有哪些因素会导致消费者消费能力差呢? 我目前的理解有三种情况 1.Du…

虚拟内存结构图

个人站点 语雀 公众号

Linux终端Tab提示忽略大小写

如图所示 在tmp目录下有两个目录,C和python 在敲击 cd c希望进入到C目录, 但是默认区分大小写, 由于敲击的是小写c, 而当前tmp目录没有小写c目录,只有大写C目录. 通过以下改动,可以实现在敲击 cd c命令的时候, 即便敲击的是小写c, 也会自动匹配大写C 改动如下 1.首先在…

Java线程在操作系统层面的一些‘蛛丝马迹‘

作为Java开发人员,在日常的开发工作中,无时无刻不在和线程打交道.本篇文章并不是讲解线程的相关知识.而是在Linux平台使用一些命令工具,观察下Java线程在操作系统层面的一些’蛛丝马迹’. 【平台】 Win10平台上安装的Ubuntu 18.04 LTS 首先从C语言层面,观察下会有几个线程或进…

操作系统之实模式和保护模式(简图)

操作系统之实模式和保护模式 分段机制和分页机制 个人站点 语雀 公众号