Redian新闻
>
ObjectMapper,别再像个二货一样一直new了!

ObjectMapper,别再像个二货一样一直new了!

公众号新闻

👉 这是一个或许对你有用的社群

🐱 一对一交流/面试小册/简历优化/求职解惑,欢迎加入芋道快速开发平台知识星球。下面是星球提供的部分资料: 

👉这是一个或许对你有用的开源项目

国产 Star 破 10w+ 的开源项目,前端包括管理后台 + 微信小程序,后端支持单体和微服务架构。

功能涵盖 RBAC 权限、SaaS 多租户、数据权限、商城、支付、工作流、大屏报表、微信公众号等等功能:

  • Boot 地址:https://gitee.com/zhijiantianya/ruoyi-vue-pro
  • Cloud 地址:https://gitee.com/zhijiantianya/yudao-cloud
  • 视频教程:https://doc.iocoder.cn

来源:小姐姐味道


前言

自从国产之光 fastjson 频频暴雷,jackson json 的使用是越来越广泛了。尤其是 Spring 家族把它搞成了默认的 JSON 处理包,jackson 的使用数量更是呈爆炸式发展。

很多同学发现,jackson 并没有类似 fastjson 的 JSON.parseObjec 这样的,确实看起来很快的方法。要想解析 json,你不得不 new 一个 ObjectMapper,来处理真正的解析动作。

就像下面这样:

public String getCarString(Car car){
    ObjectMapper objectMapper = new ObjectMapper();
    String str = objectMapper.writeValueAsString(car);
    return str;
}

这种代码就在 CV 工程师手中遍地开了花,神奇!!!

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/ruoyi-vue-pro
  • 视频教程:https://doc.iocoder.cn/video/

这代码有问题么?

你要说它有问题,它确实能正确的执行。你要说它没问题,在追求性能的同学眼里,这肯定是一段十恶不赦的代码。

一般的工具类,都是单例的,同时是线程安全的。ObjectMapper 也不例外,它也是线程安全的,你可以并发的执行它,不会产生任何问题。

这段代码,ObjectMapper 在每次方法调用的时候,都会生成一个。那它除了造成一定的年轻代内存浪费之外,在执行时间上有没有什么硬伤呢?

new 和不 new,真的区别有那么大么?

有一次,我隐晦的指出某段被频繁调用的代码问题,被小伙伴怒吼着拿出证据。

证据?这得搬出 Java 中的基准测试工具 JMH,才能一探究竟。

JMH(the Java Microbenchmark Harness)就是这样一个能够做基准测试的工具。

如果你通过我们一系列的工具,定位到了热点代码,要测试它的性能数据,评估改善情况,就可以交给 JMH。它的测量精度非常高,最高可达到纳秒的级别。

JMH 是一个 jar 包,它和单元测试框架 JUnit 非常的像,可以通过注解进行一些基础配置。这部分配置有很多是可以通过 main 方法的 OptionsBuilder 进行设置的。

上图是一个典型的 JMH 程序执行的内容。通过开启多个进程,多个线程,首先执行预热,然后执行迭代,最后汇总所有的测试数据进行分析。在执行前后,还可以根据粒度处理一些前置和后置操作。

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/yudao-cloud
  • 视频教程:https://doc.iocoder.cn/video/

JMH 测试结果

为了测试上面的场景,我们创造了下面的基准测试类。

分为三个测试场景:

  • 直接在方法里 new ObjectMapper
  • 在全局共享一个 ObjectMapper
  • 使用 ThreadLocal,每个线程一个 ObjectMapper

这样的测试属于 CPU 密集型的。我的 CPU 有 10 核,直接就分配了 10 个线程的并发,CPU 在测试期间跑的满满的。

@BenchmarkMode({Mode.Throughput})
@OutputTimeUnit(TimeUnit.SECONDS)
@State(Scope.Thread)
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(1)
@Threads(10)
public class ObjectMapperTest {
    String json = "{ \"color\" : \"Black\", \"type\" : \"BMW\" }";

    @State(Scope.Benchmark)
    public static class BenchmarkState {
        ObjectMapper GLOBAL_MAP = new ObjectMapper();
        ThreadLocal<ObjectMapper> GLOBAL_MAP_THREAD = new ThreadLocal<>();
    }

    @Benchmark
    public Map globalTest(BenchmarkState state) throws Exception{
        Map map = state.GLOBAL_MAP.readValue(json, Map.class);
        return map;
    }


    @Benchmark
    public Map globalTestThreadLocal(BenchmarkState state) throws Exception{
        if(null == state.GLOBAL_MAP_THREAD.get()){
            state.GLOBAL_MAP_THREAD.set(new ObjectMapper());
        }
        Map map = state.GLOBAL_MAP_THREAD.get().readValue(json, Map.class);
        return map;
    }

    @Benchmark
    public Map localTest() throws Exception{
        ObjectMapper objectMapper = new ObjectMapper();
        Map map = objectMapper.readValue(json, Map.class);
        return map;
    }

    public static void main(String[] args) throws Exception {
        Options opts = new OptionsBuilder()
                .include(ObjectMapperTest.class.getSimpleName())
                .resultFormat(ResultFormatType.CSV)
                .build()
;

        new Runner(opts).run();
    }
}

测试结果如下:

Benchmark                                Mode  Cnt         Score         Error  Units
ObjectMapperTest.globalTest             thrpt    5  25125094.559 ± 1754308.010  ops/s
ObjectMapperTest.globalTestThreadLocal  thrpt    5  31780573.549 ± 7779240.155  ops/s
ObjectMapperTest.localTest              thrpt    5   2131394.345 ±  216974.682  ops/s

从测试结果可以看出,如果我们每次调用都 new 一个 ObjectMapper,每秒可以执行 200 万次 JSON 解析;如果全局使用一个 ObjectMapper,则每秒可以执行 2000 多万次,速度足足快了 10 倍。

如果使用 ThreadLocal 的方式,每个线程给它分配一个解析器,则性能会有少许上升,但也没有达到非常夸张的地步。

所以在项目中写代码的时候,我们只需要保证有一个全局的 ObjectMapper 就可以了。

当然,由于 ObjectMapper 有很多的特性需要配置,你可能会为不同的应用场景分配一个单独使用的 ObjectMapper。总之,它的数量不需要太多,因为它是线程安全的。

总结

所以结论就比较清晰了,我们只需要在整个项目里使用一个 ObjectMapper 就可以了,没必要傻不拉几的每次都 new 一个,毕竟性能差了 10 倍。如果你的 JSON 有很多自定义的配置,使用全局的变量更能凸显它的优势。

不要觉得这样做没有必要,保持良好的编码习惯永远是好的。高性能的代码都是点点滴滴积累起来的。不积跬步,无以至千里。不积小流,无以成江海,说的就是这个道理。


欢迎加入我的知识星球,全面提升技术能力。

👉 加入方式,长按”或“扫描”下方二维码噢

星球的内容包括:项目实战、面试招聘、源码解析、学习路线。

文章有帮助的话,在看,转发吧。

谢谢支持哟 (*^__^*)

微信扫码关注该文公众号作者

戳这里提交新闻线索和高质量文章给我们。
相关阅读
GRE Subject专业考试改革!改为机考形式,缩短考试时长Microbiol Spectrum:科学家有望通过益生菌干预来预防和治疗结肠癌Young Chinese Obsess Over MBTI, the American Personality TestOld Markets, New Appeal: Young Chinese Rediscover Wet MarketsSUPERSTROKE NEW ZENERGY 系列:用您的反馈打造反应灵敏的推杆握把!Docker容器超全详解,别再说不会用Docker了!今夜悉尼似银河,流光溢彩冠全球究竟应该说someone faces problems还是problems face someone?Apple Pencil 1st gen with protector 15秒短视频,一直刷一直爽,别刷成了抖音脑!CVPR 2023最佳论文候选!真实高精3D物体数据集OmniObject3D这页PPT时间轴太low了,我只加了一根曲线,秒高级!CNN、GRNN、CLSTM、TD-LSTM/TC-LSTM…你都掌握了吗?一文总结情感分析必备经典模型(一)五十三 昭忠祠ICCV 2023 OmniObject3D挑战赛倒计时!双重赛道等你来战As Nolan Arrives, Chinese Fans React to ‘Oppenheimer’ Release脱了白大褂变酷飒女rapper,她们的变装让人口水直流…Hiring | B.A.A. MANAGER OF EXECUTIVE SUPPORT & PROJECTS硬核观察 #1052 libjpeg-turbo 3.0 发布,开发者表示无力继续中国内地考生托福成绩创新高/2024年Niche美国大学排名更新/GRE Subject Test 九月强势回归Meta Connect 2023定档;苹果、Adobe、皮克斯、Nvidia、Autodesk组建OpenUSD联盟FJ issues report on 130 provincial key projects in XMCharging Your Electric Car is Becoming More Expensive in ChinaAt Global Tech Meet, Firms Tackle Job Disruptions in the AI Era英语情景对话|Opposite Adjectives杂感《报任安书》和《答苏武书》并读像个男人一样活着有多爽?千万不要让你老公看到哈哈哈哈缄嘿HCSSA | 哈佛学联百家谈 X ChinaGSD - THE CITY AS A PROJECT航班取消、行李丢失、被置之不理… 加航乘客:只要求像个人一样被对待!站街女在皇后区街头雨中拉客!居民称:越来越像曼谷红灯区,而“不再像纽约了”...PPT表格太low了,为啥它这么牛!本杰明·格雷厄姆:像买杂货一样买股票[电脑] 半导体冷头 x 7800x3d -- Project CRYZEN
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。