使用ObjectMapper解析json不用一直new了
作者:小姐姐味道 发布时间:2023-11-25 05:20:10
前言
自从国产之光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工程师手中遍地开了花。
神奇。
这代码有问题么?
你要说它有问题,它确实能正确的执行。你要说它没问题,在追求性能的同学眼里,这肯定是一段十恶不赦的代码。
一般的工具类,都是单例的,同时是线程安全的。ObjectMapper也不例外,它也是线程安全的,你可以并发的执行它,不会产生任何问题。
这段代码,ObjectMapper在每次方法调用的时候,都会生成一个。那它除了造成一定的年轻代内存浪费之外,在执行时间上有没有什么硬伤呢?
new和不new,真的区别有那么大么?
有一次,xjjdog隐晦的指出某段被频繁调用的代码问题,被小伙伴怒吼着拿出证据。
证据?这得搬出Java中的基准测试工具JMH,才能一探究竟。
JMH(the Java Microbenchmark Harness) 就是这样一个能够做基准测试的工具。如果你通过我们一系列的工具,定位到了热点代码,要测试它的性能数据,评估改善情况,就可以交给JMH。它的测量精度非常高,最高可达到纳秒的级别。
JMH是一个jar包,它和单元测试框架JUnit非常的像,可以通过注解进行一些基础配置。这部分配置有很多是可以通过main方法的OptionsBuilder进行设置的。
上图是一个典型的JMH程序执行的内容。通过开启多个进程,多个线程,首先执行预热,然后执行迭代,最后汇总所有的测试数据进行分析。在执行前后,还可以根据粒度处理一些前置和后置操作。
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。总之,它的数量不需要太多,因为它是线程安全的。
End
所以结论就比较清晰了,我们只需要在整个项目里使用一个ObjectMapper就可以了,没必要傻不拉几的每次都new一个,毕竟性能差了10倍。如果你的JSON有很多自定义的配置,使用全局的变量更能凸显它的优势。
不要觉得这样做没有必要,保持良好的编码习惯永远是好的。高性能的代码都是点点滴滴积累起来的。不积跬步,无以至千里。不积小流,无以成江海,说的就是这个道理。
来源:https://juejin.cn/post/7086443387636678670


猜你喜欢
- Android手机或平板都会存在横竖屏切换的功能,通常是由物理重力感应触发的,但是有时候也不尽然,通常在设置里面我们可以对手机的横竖屏切换进
- 背景传说里玉皇大帝派龙王马上降雨到共光一带,龙王接到玉皇大帝命令,立马从海上调水,跑去共光施云布雨,但粗心又着急的龙王不小心把海里的鲸鱼随着
- 可能有些同学不明白,为啥要图片反转(不是旋转哦),我们在游戏开发中,为了节省图片资源(空间) 有可能会使用到图片反转,例如,一个人物图片,面
- 一、前言 网上有许多的多线程断点续传操作,但总是写的很云里雾里,或者
- 概要笔者近期做到对天气预报JSON数据解析,在此小记。天气预报接口:http://wthrcdn.etouch.cn/weather_min
- 不知不觉这个春节也已经过完了,遗憾家里没网,没能及时给大家送上祝福,今天回到深圳,明天就要上班了,小伙伴们是不是和我一样呢?今天讲的是一个大
- 概述HashTable是jdk 1.0中引入的产物,基本上现在很少使用了,但是会在面试中经常被问到,你都知道吗:HashTable底层的实现
- 本文实例讲述了Android使用selector修改TextView中字体颜色和背景色的方法。分享给大家供大家参考,具体如下:android
- 写在前面Linux:CentOS7.5Spark: spark-3.0.0-bin-hadoop3.2IDE:IntelliJ IDEA20
- 本文实例为大家分享了java顺时针打印矩阵的具体代码,供大家参考,具体内容如下github:剑指offer编程题 import j
- 本文实例讲述了C#导出数据到Excel文件的方法。分享给大家供大家参考。具体实现方法如下:/// <summary>/// 导出
- Android实现九宫格图案解锁,自带将图案转化成数字密码的功能,代码如下:LockPatternView.javapackage com.
- 部分情况下无法通过maven仓库直接下载需要的jar包,只能讲jar包下载至本地来使用,spring boot框架内通过maven加载第三方
- 一、相关知识SearchView控件:以下是几个简单网址:SearchView简单用法:Android搜索框(SearchView)的功能和
- 本文实例讲述了C#使用回溯法解决背包问题的方法。分享给大家供大家参考。具体如下:背包问题描述:给定一组物品,每种物品都有自己的重量和价格,在
- 经常会遇到这样的情况,我们在响应客户端请求的数据的时候需要对数据进行处理,比如数据库中的数据是int型,它可能表示某个枚举,或者其它的逻辑意
- 在使用jQuery时候,我们经常会看到或者使用到方法链,例如:$("#p1").css("color"
- 美团电商应用平台大家使用非常频繁,下面小编通过本文给大家介绍电商应用平台中常用的选择类别下拉列表的实现。先给大家展示下效果图:一、下拉列表的
- 使用RateLimiter通过AOP方式进行限流1、引入依赖<!-- guava 限流 --><dependency>
- IFormattable接口提供了ToString()方法的定义,使用该方法可以将对象的值按照指定的格式转化成字符串的功能。下面是ToStr