Netty的并发编程实践2:volatile的正确使用

2023-10-29

长久以来大家对于volatile如何正确使用有很多的争议,既便是一些经验丰富的Java设计师,对于volatile和多线程编程的认识仍然存在误区。其实,volatile的使用非常简单,只要理解了Java的内存模型和多线程编程的基础知识,正确使用volatile是不存在任何问题的。下面我们结合Netty的源码,对volatile的正确使用进行说明。

打开NioEventLoop的代码,我们来看控制I/O操作和其他任务运行比例的ioRatio,它是int类型的变量,定义如下。


我们发现,它被定义为volatile,为什么呢?我们首先对volatile关键字进行说明,然后再结合Netty的代码进行分析。

关键字volatile是Java提供的最轻量级的同步机制,Java内存模型对volatile专门定义了一些特殊的访问规则。下面我们就看它的规则。

当一个变量被volatile修饰后,它将具备以下两种特性。

◎   线程可见性:当一个线程修改了被volatile修饰的变量后,无论是否加锁,其他线程都可以立即看到最新的修改,而普通变量却做不到这点。

◎   禁止指令重排序优化,普通的变量仅仅保证在该方法的执行过程中所有依赖赋值结果的地方都能获取正确的结果,而不能保证变量赋值操作的顺序与程序代码的执行顺序一致。举个简单的例子说明下指令重排序优化问题,如图21-5所示。


图21-5  指令重排序和优化导致线程无法退出

我们预期程序会在3s后停止,但是实际上它会一直执行下去,原因就是虚拟机对代码进行了指令重排序和优化,优化后的指令如下。

if (!stop)

While(true)

   ......

重排序后的代码是无法发现stop被主线程修改的,因此无法停止运行。要解决这个问题,只要将stop前增加volatile修饰符即可。代码修改如图21-6所示。

再次运行,我们发现3s后程序退出,达到了预期效果,使用volatile解决了如下两个问题。

◎   main线程对stop的修改在workThread线程中可见,也就是说workThread线程立即看到了其他线程对于stop变量的修改。

◎   禁止指令重排序,防止因为重排序导致的并发访问逻辑混乱。

一些人认为使用volatile可以代替传统锁,提升并发性能,这个认识是错误的。volatile仅仅解决了可见性的问题,但是它并不能保证互斥性,也就是说多个线程并发修改某个变量时,依旧会产生多线程问题。因此,不能靠volatile来完全替代传统的锁。


图21-6  volatile解决指令重排序和编译优化问题

根据经验总结,volatile最适合使用的是一个线程写,其他线程读的场合,如果有多个线程并发写操作,仍然需要使用锁或者线程安全的容器或者原子变量来代替。

讲了volatile的原理之后,我们继续对Netty的源码做分析。上面讲到了ioRatio被定义成volatile,下面看看代码为什么要这样定义。参见如图21-7所示代码。


图21-7  volatile在NioEventLoop线程中的应用

通过代码分析我们发现,在NioEventLoop线程中,ioRatio并没有被修改,它是只读操作。既然没有修改,为什么要定义成volatile呢?继续看代码,我们发现NioEventLoop提供了重新设置I/O执行时间比例的公共方法,接口如图21-8所示。


图21-8  修改volatile变量

首先,NioEventLoop线程没有调用该方法,说明调整I/O执行时间比例是外部发起的操作,通常是由业务的线程调用该方法,重新设置该参数。这样就形成了一个线程写、一个线程读。根据前面针对volatile的应用总结,此时可以使用volatile来代替传统的synchronized关键字提升并发访问的性能。

Netty中大量使用了volatile来修改成员变量,如果理解了volatile的应用场景,读懂Netty volatile的相关代码还是比较容易的。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Netty的并发编程实践2:volatile的正确使用 的相关文章

  • Tor 介绍

    Tor The Onion Router 是第二代洋葱路由 onion routing 的一种实现 用户通过Tor可以在因特网上进行 匿名交流 最初该项目由 美国海军研究实验室 US Naval Research Laboratory 赞助
  • 【HeadFirst 设计模式学习笔记】1.策略模式

    1 书中举了一个鸭子类的设计 有些会飞或者会叫 有些不会飞可能也不会叫 用继承则导致不该有的功能通过继承而继承了下来 使用接口则代码无法做到最大程度的重用 进而引出设计原则1 找出应用中可能需要变化之处 把它们独立出来 不要和那些不需要变化
  • 记一次计算机网络工程实验(1) 利用VLAN划分不同网段

    一学期没上过计算机网络工程的课 今天是第一次去做实验 把经验记在这里 免得过几天又忘了 安装Cisco Packet Tracer 首先需要下载和安装这次实验的工具 Cisco Packet Tracer 这是一个模拟路由器 交换机和各种终
  • 做交互设计都有哪些需要掌握的思维方式

    由于目前的环境对这个细分领域仍然缺乏了解 我希望在这篇文章中写一些交互设计所需的思维方式 1 可用性优先 视觉靠边 一个功能个功能应该能够使用和使用 以便有人关心它是否好看 审美挑剔的用户实际上比你想象的要少得多 当然 这并不是说视觉设计并
  • 学习UI设计有哪些figma插件

    自2016年推出以来 Figma已发展成为市场领先者UI设计工具之一 因为它不仅简单易用 功能优秀 而且基于云服务 可以实时编辑 节省大量手动下载或复制文件的时间 不仅如此 Figma还提供合作功能 让您和您的团队同时处理文件 避免许多潜在
  • 浅谈依赖注入

    最近几天在看一本名为Dependency Injection in NET 的书 主要讲了什么是依赖注入 使用依赖注入的优点 以及 NET平台上依赖注入的各种框架和用法 在这本书的开头 讲述了软件工程中的一个重要的理念就是关注分离 Sepa
  • 思科模拟器基础实验完整流程-初级

    文章目录 实验拓扑 第一部分 企业总部内网 第一层 接入层 第二层 汇聚层 解决 VLAN 间通信 第三层 网络层 第二部分 企业分部内网 第三部分 外部网络路由 第四部分 NAT 地址转换 第五步 VPN 实验拓扑 由图我们可以看到这张拓
  • UML用例图的作用、功能模块图作用与数据库设计三者关系

    这周周一 我们导师要求小组成员开会 我们分别汇报自己的工作 在会中 谈到了用例图 于是我们开始对大家熟悉的用例图进行探讨 经过探讨与自己的思考 我认为应该从以下几个问题来弄清楚用例图的作用 1 用例图由谁来做 为谁做 做完了有什么用途 用例
  • 探究:kafka生产者/消费者与多线程安全

    目录 1 多线程安全 1 1 生产者是多线程安全的么 1 1 消费者是多线程安全的么 2 消费者规避多线程安全方案 2 1 每个线程维护一个kafkaConsumer 2 2 单 多 kafkaConsumer实例 多worker线程 2
  • 一个完整的产品设计都要哪些设计流程

    设计理念是抽象的 它描述了一个产品从概念到完成的一般过程 然而 真正的产品设计过程要复杂得多 也要具体得多 因此 我们将分解这个过程中最重要的部分 并给实践中使用的建议 1 设计前期 通常 设计过程的第一步在产品设计之前就已经开始了 这是因
  • 私网地址与Internet地址

    一 A B C三类地址 可用地址范围 备注 A类 1 0 0 1 126 255 255 254 B类 128 1 0 1 191 255 255 254 C类 192 0 1 1 223 255 255 254 D类 224 0 0 1
  • 生产者消费者模型你知道多少

    背景 进入正题之前先说点故事 从最开始学java的那里开始 我是从08年下半年开始学Java 在 我的六年程序之路 中提到了一些 当时比较简单 每天看尚学堂的视频 对于初学者而言看视频好一些 然后写代码 比较清楚的记得马士兵讲到生产者消费者
  • 学习笔记(5):MySQL数据库从入门到实战应用-数据完整性

    立即学习 https edu csdn net course play 27328 362521 utm source blogtoedu 实体完整性 要求每张表都有唯一标识符 每张表主键字段不为空且不能重复 唯一性约束 主键约束 标识列
  • Wire load model

    做综合时 经常提到wire loadmodel 一直不甚了解 只知道是针对0 18um以上的工艺的一种粗略估计线延迟的模型方法 最近有时间看primepower的文档 终于有一些理解了 Wireload模型 实际上就是综合库中 若干个fan
  • App6种常见的数据加载设计

    设计师在进行APP设计的设计时 往往会更加专注于界面长什么样 界面和界面之间怎么跳转 给予用户什么样的操作反馈 却偏偏特别容易忽略掉一个比较重要的环节 就是APP数据加载中的设计 所以会导致我们看到的APP 往往有着华丽的启动界面 然后就是
  • 完全免费快速搭建个人www服务器

    想拥有自己的web服务器吗 想把服务器放到自己家里吗 通过ADSL拨号也能建立个人的服务器吗 本文告诉你答案 要建立自己的web服务器 需要两个最重要的工作 1 让别人知道你的主机 目前访问Internet上主机的方式主要有两种 一是通过I
  • Django 快速搭建博客 第三节(数据库表设计)

    上一节我们已经能在pycharm下新建了blog app了 这个时候 我们需要设计一下博客的数据库设计 关于数据库表的设计 作为新手的我们并不需要要求懂太多稍微的懂一些也就可以了 毕竟数据库也是需要有一定的功底的 这里我们依据博客学习 将博
  • 原型设计都有哪些好用的软件?

    原型图的设计软件只多不少 许多新人设计师都不知道怎么样在这些琳琅满目的选择中找到适合自己的 而且也不清楚主流软件究竟是哪些 接下来 本文将主要为大家介绍这方面知识 其实原型图设计有许多软件工具可选择 具体选择哪一款软件还是要取决于原型所需的
  • 试题库管理系统--数据库设计

    链接 https pan baidu com s 1ilMGCA n1GPDk3O8k7w7Gg 提取码 m0ke 复制这段内容后打开百度网盘手机App 操作更方便哦 一 概要设计 1 1 背景和意义 目前 许多高校绝大多数课程还采用考教统
  • 电脑快速打开计算器的方法

    大家好 我是爱你三千遍斯塔克 我们平常在运算时 经常要要使用计算器 那么计算器有什么快速打开方法吗 这里有一些参考方法 可供大家进行参考 希望对大家有帮助 希望你喜欢我的内容 记得关注我哦 我会继续为大家带来更好的作 1 win R 打开运

随机推荐

  • 固态硬盘usb测试软件,固态硬盘检测修复坏道三级OP设置软件HDAT2 5.3 ISO版

    HDAT2是用于测试或诊断硬盘 SSD和USB设备的程序 这里分享的是iso版 更新日期是2016年11月 你必须把它用ultraiso做成U盘启动盘 启动电脑后在dos环境下使用 这里介绍的主要功能是修复ssd的坏道 也就是Secure
  • 创建一个自定义插件,实现一个登录页面

    运行结果如下 话不多说 直接开整 div div
  • 05【掌握】 SpringBoot 清空Redis所有缓存

    package top yangbuyi system controller import org springframework beans factory annotation Autowired import org springfr
  • css3顺时,CSS3(transforms)

    transforms 主要包括了两个属性 transform 只可以转换 由盒子模型定位的元素 而根据经验也就是 具备了display block这个属性 由盒子模型定位元素 transform 指定作用在元素上的变形 取值为空格分隔的一些
  • Spring Cloud灰度部署

    1 背景 灰度部署 在我们系统发布生产环境时 有时为了确保新的服务逻辑没有问题 会让一小部分特定的用户来使用新的版本 比如客户端的内测版本 而其余的用户使用旧的版本 那么这个在Spring Cloud中该如何来实现呢 负载均衡组件使用 Sp
  • 【安卓学习之工具学习】网络通信测试工具-socket/post/get

    在安卓开发中 网络请求基本上都有用到 有时候我们通信出现问题 我们不知道是服务端问题还是客户端问题 就可以使用第三方的工具来测试 以保证能更好的确定出现bug的方向 当然也有时候接手别人开发的app 但又不知道里面的通信协议 也可以通过这个
  • Visio制图拷贝到word文档中显示不全、只显示一行

    问题描述 Visio 2016绘制技术流程图完毕 拷贝到Word 2016中时 只显示一行 最底部部分 上面其他部分只能看到最外边边框其他部分侵入上方文本区 且不显示 解决方案 选中要插入的行 设置行间距为1 5倍 我的问题是解决了 欢迎补
  • NVDLA系列之C-model:cvif<100>

    NV NVDLA cvif cpp pdp2cvif wr req b transport void NV NVDLA cvif pdp2cvif wr req b transport int ID nvdla dma wr req t p
  • JDBC中对url的一些理解

    大家都知道 用java来连接数据库 一般都是class forName 然后用DriverManager来生成一个Connection 生成Connection的method为 DriverManager getConnection 其中里
  • STM32_USART 串口通讯

    STM32 USART 串口通讯 通信方式的分类 按照通信方式分类 按照数据传送方向分类 通信接口及其说明如下图所示 STM32的串口通信 引脚接线 串口通讯的过程 串口发送数据 串口接收数据 USART中断请求 通信方式的分类 按照通信方
  • 【数据库1】mysql,DDL/DML/DQL,外键约束/多表/子查询,事务/连接池

    文章目录 1 mysql安装 存储 集合 内存 临时 IO流 硬盘 持久化 1 1 服务端 双击mysql installer community 5 6 22 0 msi 1 2 客户端 命令行输入mysql u 实际是如下安装路径的bi
  • 计算机怎么把硬盘分成几个,如何把电脑的一个盘的容量分给另外一个盘

    把电脑中的一个分区闲置容量分去给另外一个分区 今天就来分享如何把其中一个分区的闲置容量分去另外一个分区 以我的操作为例子 如我要把 F盘 的闲置2G空间 分给 G盘 如图所示 F盘是 4 99GB 的容量 G盘是 2 99GB 的容量 首先
  • uboot中启动linux内核的函数——do_bootm_linux函数解析

    1 do bootm linux函数解析 do bootm linux函数是专门启动linux内核的 包括以下功能 1 确认当前的机器码 可以从全局变量gd或者环境变量machid中获取 其中环境变量machid的优先级高于gd中的机器码
  • 禁欲28天!一宅男居然肝出如此详细Web安全学习笔记,学妹看完直接抽搐了!(持续中出)

    1 1 Web技术演化 1 1 1 简单网站 1 1 1 1 静态页面 Web技术在最初阶段 网站的主要内容是静态的 大多站点托管在ISP上 由文字和图片组成 制作和表现形式也是以表格为主 当时的用户行为也非常简单 基本只是浏览网页 1 1
  • 笔记整理-多线程与高并发

    多线程与高并发 目录 多线程与高并发 https www cnblogs com Zs book1 p 14318992 html share token 641d3935 0525 44d5 a772 9764bf2fad2a 一 了解多
  • SQL注入 fuzz字典

    fuzz x23 x27 x3D x3B x3D x27 x27 x4F x52 SELECT x27 x6F x72 SELECT or select admin shutdown lt gt or or x x or x x or x
  • 在使用node.js时发现的问题,npm版本版本过低,升级报错

    博主 之前安装nodejs 并没有通过nvm来控制 后面发现nvm很好用 就直接安装nvm使用 但没有把之前安装的nodejs版本删掉 就导致出现了很多很多的bug 找原因找太久 就想发文记入一下 问题一 nvm中切换不了nodejs版本
  • Android内存压力测试工具(memtester移植)

    该文章转载于 android用memtester内存压力测试 W歹匕示申W的博客 CSDN博客 Android内存压力测试工具 memtester移植 甜牛奶蛋糕的博客 CSDN博客 android 内存压力测试 DRR参考配置OK之后 首
  • 当下,最适合地产人的副业来了

    人无远虑 必有近忧 对于这两年的地产人来说 更是如此 大裁员 大降薪 叠加yi情的反复侵扰 地产人的生存处境似乎越来越糟糕 你会发现身边只能靠着工资养家的人 在行业动荡期无疑是被动和焦虑的 还担心突如其来的裁员 挣钱不易 人 总得提前为自己
  • Netty的并发编程实践2:volatile的正确使用

    长久以来大家对于volatile如何正确使用有很多的争议 既便是一些经验丰富的Java设计师 对于volatile和多线程编程的认识仍然存在误区 其实 volatile的使用非常简单 只要理解了Java的内存模型和多线程编程的基础知识 正确