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

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.kler.cn/a/531012.html

相关文章:

  • 51单片机(STC89C52)开发:点亮一个小灯
  • 网络协议基础
  • 求职刷题力扣DAY34--贪心算法part05
  • 【Elasticsearch】_all 查询
  • HTML5 技术深度解读:本地存储与地理定位的最佳实践
  • 面试问题知识
  • 49【服务器介绍】
  • 常见的 Vue.js 组件库:Element Plus, Vuetify, Quasar
  • NeuralCF 模型:神经网络协同过滤模型
  • docker pull Error response from daemon问题
  • [HOT 100] 2824. 统计和小于目标的下标对数目
  • FreeRTOS从入门到精通 第十九章(内存管理)
  • 【大数据技术】教程05:本机DataGrip远程连接虚拟机MySQL/Hive
  • 《tcp/ip协议详解》,tcp/ip协议详解
  • Vue-data数据对象
  • 列表的简介
  • 新月军事战略分析系统使用手册
  • Linux中的基本指令(二)
  • Deep Crossing:深度交叉网络在推荐系统中的应用
  • 洛谷 P8724 [蓝桥杯 2020 省 AB3] 限高杆
  • 深入理解Java虚拟线程的同步编程模型
  • C++泛型编程指南09 类模板实现和使用友元
  • CSS整体回顾
  • 自动驾驶---两轮自行车的自主导航
  • 【Linux系统】—— make/makefile
  • RRT_STAR路径规划代码