Why Reusing a Single Jackson ObjectMapper Boosts JSON Parsing Speed 10×
Using Jackson's ObjectMapper for JSON parsing, this article benchmarks three approaches—creating a new mapper per call, sharing a global singleton, and using ThreadLocal—revealing that a single shared ObjectMapper can achieve up to ten times higher throughput, while ThreadLocal offers only modest gains.
Background
After frequent security issues with fastjson, Jackson has become the default JSON processor in the Spring ecosystem, leading to widespread adoption.
Typical usage
Unlike fastjson’s JSON.parseObject, Jackson requires creating an ObjectMapper instance to perform parsing, as shown below.
public String getCarString(Car car) {
ObjectMapper objectMapper = new ObjectMapper();
String str = objectMapper.writeValueAsString(car);
return str;
}Although this code works, creating a new mapper for every call can waste memory and affect performance.
Thread‑safety of ObjectMapper
ObjectMapper is thread‑safe, so a single instance can be shared across threads without issues.
Benchmarking with JMH
To measure the impact of different instantiation strategies, the Java Microbenchmark Harness (JMH) is used. Three scenarios are benchmarked:
Instantiate a new ObjectMapper inside the method.
Use a globally shared singleton ObjectMapper.
Assign an ObjectMapper to each thread via ThreadLocal.
The benchmark class is shown below.
@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 {
return state.GLOBAL_MAP.readValue(json, Map.class);
}
@Benchmark
public Map globalTestThreadLocal(BenchmarkState state) throws Exception {
if (state.GLOBAL_MAP_THREAD.get() == null) {
state.GLOBAL_MAP_THREAD.set(new ObjectMapper());
}
return state.GLOBAL_MAP_THREAD.get().readValue(json, Map.class);
}
@Benchmark
public Map localTest() throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(json, Map.class);
}
public static void main(String[] args) throws Exception {
Options opts = new OptionsBuilder()
.include(ObjectMapperTest.class.getSimpleName())
.resultFormat(ResultFormatType.CSV)
.build();
new Runner(opts).run();
}
}An illustration of a typical JMH execution flow:
The benchmark results are:
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/sFindings
Creating a new ObjectMapper for each call yields about 2 million operations per second, while reusing a single global instance reaches roughly 20 million ops/s—a ten‑fold improvement. ThreadLocal provides a modest increase over the global singleton but not a dramatic one.
Conclusion
Because ObjectMapper is thread‑safe, projects should maintain a single shared instance (or a few configured instances) rather than instantiate it repeatedly. This practice improves performance and promotes cleaner code.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java Backend Technology
Focus on Java-related technologies: SSM, Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading. Occasionally cover DevOps tools like Jenkins, Nexus, Docker, and ELK. Also share technical insights from time to time, committed to Java full-stack development!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
