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

volatile变量需要减少读取次数吗

问题说明

本人在前期读Netty源码时看到这样一段源码和注释:

private boolean invokeHandler() {// Store in local variable to reduce volatile reads.int handlerState = this.handlerState;return handlerState == ADD_COMPLETE || (!ordered && handlerState == ADD_PENDING);}

此源码见于io.netty.channel.AbstractChannelHandlerContext,其中的handlerState 是一个volatile修饰的状态量。在此方法中,需要两次使用handlerState变量。在我看来,这段代码中没有必要先使用局部变量handlerState 来保存volatile修饰的成员变量handlerState 。这样写似乎更简洁:

private boolean invokeHandler() {return handlerState == ADD_COMPLETE || (!ordered && handlerState == ADD_PENDING);}

Netty这段的注释给出了增加先使用局部变量handlerState 来保存volatile修饰的成员变量handlerState这行代码的理由:Store in local variable to reduce volatile reads。其意思为,存入本地变量来减少volatile类型属性的读取。

大概解释

鄙人多方查找资料,寻找这样做的原因,下面的这段解释似乎合理:

在编程中,减少对易变(volatile)变量的读取次数可以是一种优化技术,尤其是在并发编程中。这是因为频繁地从易变变量中读取数据可能会引入不必要的延迟,尤其是在高竞争的环境下。为了提高性能和减少延迟,你可以通过将易变变量的值存储在局部变量中来减少对它的直接访问。

为什么要减少易变变量(volatile)的读取?
性能优化:频繁读取易变变量可能会引入不必要的缓存失效和总线流量,特别是在多核处理器上。

避免竞态条件:虽然易变性本身是为了解决可见性问题,但过多的读取可能导致竞态条件的风险增加。

代码验证

为了严重在并发环境下频繁访问volatile变量时,直接读取和先读取存入局部变量两种方式性能差异,本人采用如下代码验证。
测试结果显示两种方式耗时差不多!对于这样的结果,是我的验证方式不准确,还是Netty源码中的先将volatile变量存入本地局部变量的做法是冗余代码,欢迎大家批评指正。

public class VolatileTest {static volatile int num = 5;static CountDownLatch latch = new CountDownLatch(20);public static void main(String[] args) throws InterruptedException {// 创建一个包含10个线程的固定线程池ExecutorService executor = Executors.newFixedThreadPool(10);//向线程池提交20个任务long start = System.currentTimeMillis();for (int i = 0; i < 20; i++) {executor.execute(() -> {for(int x = 0 ;x < 1000000 ; x++){//方式一:直接每次读取num来使用/** if(VolatileTest.num == 10){** }** if(VolatileTest.num > 5){** }** if(VolatileTest.num >7){** }* *///方式二:先读取num存入本地的局部变量int numLocal = VolatileTest.num;if(numLocal == 10){}if(numLocal > 5){}if(numLocal >7){}}latch.countDown();});}latch.await();long stop = System.currentTimeMillis();System.out.println(stop-start);// 关闭线程池executor.shutdown();}
}
http://www.lryc.cn/news/531110.html

相关文章:

  • bootstrap.yml文件未自动加载问题解决方案
  • 编程AI深度实战:AI编程工具哪个好? Copilot vs Cursor vs Cody vs Supermaven vs Aider
  • 前端知识速记--CSS篇:display
  • 51单片机 01 LED
  • WPF进阶 | WPF 动画特效揭秘:实现炫酷的界面交互效果
  • 分页按钮功能
  • 数据分析系列--⑦RapidMiner模型评价(基于泰坦尼克号案例含数据集)
  • 集合通讯概览
  • 【FreeRTOS 教程 八】直达任务通知
  • Ubuntu 18.04安装Emacs 26.2问题解决
  • nodejs:js-mdict 的下载、安装、测试、build
  • CSS关系选择器详解
  • Python在线编辑器
  • 蓝桥杯备考:高精度算法之除法
  • 笔试-业务逻辑4
  • 《Linux服务与安全管理》| 数据库服务器安装和配置
  • 麦芯 (MachCore) 应用开发教程 6:一台设备中多台电脑主从机的设置
  • RAG 与历史信息相结合
  • 99,[7] buuctf web [羊城杯2020]easyphp
  • BUUCTF_[安洵杯 2019]easy_web(preg_match绕过/MD5强碰撞绕过/代码审计)
  • Vue05
  • ubuntu18.04环境下,Zotero 中pdf translate划线后不翻译问题解决
  • 基于Python的简单企业维修管理系统的设计与实现
  • 【C++】B2120 单词的长度
  • 2501,编写dll
  • 【router路由的配置】
  • 算法基础——一致性
  • 刷题记录 动态规划-6: 62. 不同路径
  • docker直接运行arm下的docker
  • 014-STM32单片机实现矩阵薄膜键盘设计