当前位置: 首页 > news >正文

Netty源码解析-锁机制

Netty基本介绍,参考 Netty与网络编程

为了提高性能,Netty对锁也做了大量优化

1、锁优化技术

Netty大量使用了锁优化技术:

  • 1.1 减小锁粒度
  • 1.2 减少锁对象的空间占用
  • 1.3 提高锁的性能
  • 1.4 根据不同业务场景选择合适锁
  • 1.5 能不用锁则不用锁

1.1 减小锁粒度

在Netty4.1.15.Final版本中ServerBootstrap.init方法中有两个地方对对象加锁,而不是在方法上加一个大锁,缩小了锁范围,如下图
在这里插入图片描述

1.2 减少锁对象的空间占用

源码ChannelOutboundBuffer类,如下图:

totalPendingSize是用来统计待发送字节数的,上面的TOTAL_PENDING_SIZE_UPDATER是AtomicLongFieldUpdater类型的,它实现对ChannelOutboundBuffer的totalPendingSize属性进行加锁累加,实现一个类似AtomicLong的功能。(下面的unwritable一样的道理)

在这里插入图片描述

那么为什么要这么做呢?为什么不直接使用AtomicLong来定义totalPendingSize?

为了节省空间

AtomicLong  VS  long + AtomicLongFieldUpdater(帮助long完成原子操作)
类型占用空间
AtomicLong对象头16B + 8B数据 + 8引用 =至少32B
long8B
直接使用long,节省20多个字节,虽然很少,但是作为一个网络工具,在大流量的情况下可以节省出很多空间,还是很有意义的

1.3 提高锁性能

1.3.1 我们看一下PlatformDependent.LongCounter方法如何做的?

源码PlatformDependent,这个类里面有很多类似代码
在这里插入图片描述

该方法提供了一个Long类型的线程安全累加器,针对java版本8以后和8以前的提供的累加器不一样

1.8及后  LongAdder   VS  AtomicLong(1.8)

因为LongAdder是1.8版本开始增加的新的Long累加器,在高并发是性能要优于AtomicLong,所以1.8版本以后使用LongAdder

1.3.2 LongAdder和AtomicLong

  • AtomicLong 对Long类型进行原子读写
  • LongAdder将Long的值value分成若干个cell,高并发是对某个cell的值累加,可以同时对多个cell值进行累加,能支持更高的并发。需要取到value就对所有cell进行一次sum就可以了
    在这里插入图片描述

1.3.3 我们做一个简单的测试看一下LongAdder和AtomicLong的性能:

public class LongAdderTest {public static void main(String[] args) {testAtomicLongVSLongAdder(10, 10000);System.out.println("==================");testAtomicLongVSLongAdder(10, 200000);System.out.println("==================");testAtomicLongVSLongAdder(100, 200000);}//AtomicLong与LongAdder多线程并发模拟及耗时统计static void testAtomicLongVSLongAdder(final int threadCount, final int times) {try {long start = System.currentTimeMillis();testLongAdder(threadCount, times);long end = System.currentTimeMillis() - start;// System.out.println("条件>>>>>>线程数:" + threadCount + ", 单线程操作" + times);System.out.println("LongAdder--count" + (threadCount * times) + ",time:" + end);long start2 = System.currentTimeMillis();testAtomicLong(threadCount, times);long end2 = System.currentTimeMillis() - start2;System.out.println("Atomic--count" + (threadCount * times) + ",time:" + end2);} catch (InterruptedException e) {e.printStackTrace();}}//使用AtomicLong模拟i++多线程并发:threadCount线程数、times每个线程运行多少次static void testAtomicLong(final int threadCount, final int times) throws InterruptedException {CountDownLatch countDownLatch = new CountDownLatch(threadCount);//发令枪:确保多线程同时运行AtomicLong atomicLong = new AtomicLong();for (int i = 0; i < threadCount; i++) {new Thread(new Runnable() {@Overridepublic void run() {for (int j = 0; j < times; j++) {atomicLong.incrementAndGet(); //++操作}countDownLatch.countDown();}}, "my-thread" + i).start();}countDownLatch.await();}//使用LongAdder模拟i++多线程并发:threadCount线程数、times每个线程运行多少次static void testLongAdder(final int threadCount, final int times) throws InterruptedException {CountDownLatch countDownLatch = new CountDownLatch(threadCount);LongAdder longAdder = new LongAdder();for (int i = 0; i < threadCount; i++) {new Thread(new Runnable() {@Overridepublic void run() {for (int j = 0; j < times; j++) {longAdder.add(1);//是原子操作,多线程安全  //++操作}countDownLatch.countDown();}}, "my-thread" + i).start();}countDownLatch.await();}
}

运行结果

如下图,高并发情况下LongAdder性能显著高于AtomicLong
在这里插入图片描述

1.4 根据不同的业务场景选择合适的锁

SingleTreadEventExecutor中定义了Atomic…类型、CountDownLatch形式的锁在不同的地方使用
在这里插入图片描述

1.5 能不用锁就不用锁

我们Netty源码的Recycler类里面有一个属性threadLocal,他是FastThreadLocal类型,该来对jdk提高的ThreadLocal做了一层包装,该类有一个虚方法onRemoval,使用该类必须实现这个方法,避免内存泄露。

ThreadLocal是线程私有的,使用这个东西可以避免线程操作共享变量的并发竞争。
在这里插入图片描述

总结

从上面的讨论的五种锁优化技术可以看出来,Netty对锁的优化可以说做到极致,各种场景下都对锁的优化有大量使用,这也是Netty高性能的一个重要原因,这些值得我们学习在项目中使用。

http://www.lryc.cn/news/446617.html

相关文章:

  • 【C/C++】initializer_list
  • 不要再混淆啦!一文带你学会原型链继承、构造函数继承、寄生组合继承、ES6继承
  • 828华为云征文|华为云Flexus X实例Windows Server 2019安装护卫神防火墙——为企业运维安全发挥重要作用!!!
  • 最新的iOS 18版本和Android 15版本系统分别升级了哪些功能?
  • window系统DockerDesktop 部署windows容器
  • CSDN文章导出md并迁移至博客园
  • 计算机组成原理(笔记5原码和补码的乘法以及直接补码阵列乘法器 )
  • 【hot100-java】【括号生成】
  • k8s_资源管理介绍
  • 操作简单 地检编码器 武汉正向科技售后优质
  • 2024中国新能源汽车零部件交易会,开源网安展示了什么?
  • Java解析嵌套jar中class文件
  • 【含文档】基于Springboot+Vue的高校竞赛管理系统(含源码+数据库+lw)
  • 在大模型应用层面区分对比检索增强生成RAG技术和知识库技术
  • 云和恩墨携手华为,发布zCloud数据库备份管理一体机并宣布共建数据保护生态...
  • Linux系统备份Gitee等云git所有仓库与所有分支的数字资产
  • JavaScript 条件循环语句
  • LeetCode2207解题思路
  • opencv图像增强十四:opencv两种白平衡介绍及实现
  • Linux标准IO(四)-格式化I/O输入
  • 分布式安装LNMP
  • TFTP协议
  • FPGA随记-二进制转格雷码
  • Android常用C++特性之std::unique_lock
  • 网络与信息安全工程师(工信部教育与考试中心)
  • uni-app+vue3开发微信小程序使用本地图片渲染不出来报错[渲染层网络层错误]Failed to load local image resource
  • Leetcode 93-复原 IP 地址
  • unity 中向指定的动画片段添加动画事件,并播放动画,同时获取动画片段的时长。
  • JavaEE:探索网络世界的魅力——玩转UDP编程
  • 生成式人工智能:企业数字化转型的全新引擎,深度解析The Open Group 2024生态系统架构·可持续发展年度大会