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

对于自带缓存的对象的注意点

背景

看到某个发的一个他遇到的bug,觉得有意思,特此记录一下。
他的bug现象:一次kafka消费,代码没发现任何问题,就是始终没有消费到数据。后面在日志中发现本应该初始化offset=0的,变成了offset=1590039403;
发现是程序里面调用了一个
public native int GetConfFile(String var1, int var2, StringBuffer var4);
的本地方法

  1. java中某些对象自带有缓存功能:如Integer、Long、Character、Byte等。调用这些类的valueOf()方法,如果是在缓存范围内的数都是获取的缓存对象,而不会创建新对象。
  2. 这些对象可以自动拆箱装箱。
  3. 对于同一个对象,不管谁修改了它,其他地方用到了这个对象的也会发生改变。

Thread t = new Thread(() -> {
            Integer a = 0;
            while (true) {
                System.out.println(a);
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (Throwable ignore) {
                }
            }
        });
t.start();

当我们执行上述代码时,理论上a的值应该一直的0的,因为没有任何地方修改这个a。

Thread t = new Thread(() -> {
            Integer a = 0;
            while (true) {
                System.out.println(a);
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (Throwable ignore) {
                }
            }
        });
        t.start();
        TimeUnit.SECONDS.sleep(5);
        // 定义一个b,下面是模拟修改b的值
        Integer b = 0;
        // 获取Unsafe的实例
        Field f = Unsafe.class.getDeclaredField("theUnsafe");
        f.setAccessible(true);
        Unsafe unsafe = (Unsafe) f.get(null);
        // 获取对象的字段
        Field field = Integer.class.getDeclaredField("value");
        // 计算字段在对象中的偏移量
        long offset = unsafe.objectFieldOffset(field);
        // 修改字段的值
        unsafe.putInt(b, offset, 1);
        System.out.println("+++++" + unsafe.getInt(b, offset));

然后试试执行上面代码,可以看到线程里面的a还是没有谁去修改它,下面定义了一个b,然后后面模拟修改b对应的值,后面发现a的输出值夜变了。

  1. 缓存对象是同一个对象,内存地址是同一个;
  2. 某些方法里面会调用native方法,底层是c++,而c++通常传递的是指针,也就是对象的内存地址,c++修改这个内存对应的值;
  3. 如果刚好被修改的这个参数是一个被缓存共用的对象,那所有使用这个缓存对象的都会发生改变。

http://www.kler.cn/a/377794.html

相关文章:

  • java项目之校园周边美食探索及分享平台(springboot)
  • C#中JsonConvert.DeserializeObject方法
  • 语音识别ic赋能烤箱,离线对话操控,引领智能厨房新体验
  • Docker安装MongoDB详解(mongo.latest)
  • yolov8涨点系列之引入CBAM注意力机制
  • StandardThreadExecutor源码解读与使用(tomcat的线程池实现类)
  • 8. 数据结构——邻接表、邻接矩阵的基本操作
  • Elasticsearch Search Template 搜索模板
  • 代码随想录算法训练营第十五天| 654.最大二叉树 、617.合并二叉树 、700.二叉搜索树中的搜索、98.验证二叉搜索树
  • AcWing 320 能量项链 状态压缩dp
  • 【C++刷题】力扣-#566-重塑矩阵
  • 前端八股文第四篇
  • WorkFlow源码剖析——Communicator之TCPServer(上)
  • Linux:编辑器Vim和Makefile
  • ResTful风格的Url
  • Mac如何实现高效且干净的卸载应用程序
  • Gateway解说
  • 目标追踪DeepSort
  • network HCIE认证
  • 一文带你深入理解Rust 中的 Trait 一致性(Coherence)
  • SparkSQL整合Hive后,如何启动hiveserver2服务
  • Spring Boot框架下的水电管理系统开发
  • leetcode-21-合并两个有序链表
  • mac电脑设置crontab定时任务,以及遇到的问题解决办法
  • 【力扣专题栏】两数之和,两种解法实现该题。
  • python数据类型-8-数据结构-Queue (队列)